C99 defines undefined behavior in Section The C Standard, subclause 3.4.3 as:[ISO/IEC 9899:2011], defines undefined behavior as
behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements.
C99 Section Subclause 4 explains how the standard identifies undefined behaviors:behavior (see also undefined behavior 1 of Annex J).
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, subclause J.2, "Undefined behavior" contains a list of explicit undefined behaviors in C99," enumerates the circumstances under which the behavior of a program is undefined. This list is duplicated on the CC. Undefined Behavior page.
Behavior can be classified as undefined by the C standards committee for a variety of the following reasons including:
- The behavior is erroneous.
- The behavior is difficult to diagnose.
- As a hook for implementation extensions.
:
- To give the implementor license not to catch certain program errors that are difficult to diagnose
- To identify areas of possible conforming language extension: the implementor may augment the language by providing a definition of the officially undefined behavior
Conforming implementations can Conforming implementation cans deal with undefined behavior in a variety of fashions, from such as ignoring the situation completely, with unpredictable results, to behaving during translation or program execution ; translating or executing the program in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to ; or 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 candidates for optimization. By assuming that undefined behaviors will not occur, compilers can generate code with better performance characteristics.Unfortunately
, Increasingly, compiler writers are taking advantage of 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 outin the C programming languages to improve optimizations. These optimizations frequently interfere with the ability of developers to perform cause-effect analysis on their source code—that is, to analyze the dependence of downstream results on prior results. Consequently, these optimizations are eliminating causality in software and are increasing the probability of software faults, defects, and vulnerabilities.
All of this puts the onerous onus on the programmer to write conforming applicationsdevelop code that is free from undefined behaviors, 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.
...
Noncompliant Code Example
An example of undefined behavior in C99 C is the behavior on signed integer overflow . This non-compliant (see also INT32-C. Ensure that operations on signed integers do not result in overflow). This noncompliant code example depends on this behavior to catch the overflow:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <assert.h> #include <assert<limits.h> #include <stdio.h> int foo(int a) { assert(a + 100 > a); printf("%d %d\n", a + 100, a); return a; } int main(void) { foo(100); foo(INT_MAX); return 0; } |
This code tests checks for signed integer overflow by testing to see if whether a + 100 > a
. This test cannot evaluate to true false unless an integer overflow occurs. However, because a conforming implementation is not required to generate code for undefined behavior, and signed integer overflow is undefined behavior, this code may be compiled out. For example, gcc version GCC 4.1.1 optimizes out the assertion for all optimization levels, and gcc GCC 4.2.3 optimizes out the assertion for program programs compiled with -O2
-level optimization and higher.
On some platforms, the integer overflow causes the program to terminate (before it has an opportunity to test).
Compliant Solution
This compliant solution does not depend on undefined behavior:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <assert.h> #include <assert<limits.h> #include <stdio.h> int foo(int a) { assert(((a < 0) || (a < (INT_MAX - 100)))); printf("%d %d\n", a + 100, a); return a; } int main(void) { foo(100); foo(INT_MAX); return 0; } |
Risk Assessment
Unused values may indicate significant logic errors, possibly resulting in a denial of service conditionAlthough it is rare that the entire application can be strictly conforming, the goal should be that almost all the code is allowed for a strictly conforming program (which among other things means that it avoids undefined behavior), with the implementation-dependent parts confined to modules that the programmer knows are needed to adapt to the platform when it changes.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC15- |
low
unlikely
medium
P2
C | High | Likely | Medium | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| Supported: Astrée reports undefined behavior. | |||||||
Helix QAC |
| C0160, C0161, C0162, C0163, C0164, C0165, C0166, C0167, C0168, C0169, C0170, C0171, C0172, C0173, C0174, C0175, C0176, C0177, C0178, C0179, C0184, C0185, C0186, C0190, C0191, C0192, C0193, C0194, C0195, C0196, C0197, C0198, C0199, C0200, C0201, C0203, C0204, C0206, C0207, C0208, C0235, C0275, C0301, C0302, C0304, C0307, C0309, C0323, C0327, C0337, C0400, C0401, C0402, C0403, C0475, C0543, C0544, C0545, C0602, C0603, C0623, C0625, C0626, C0630, C0632, C0636, C0654, C0658, C0661, C0667, C0668, C0672, C0676, C0678, C0680, C0706, C0745, C0777, C0779, C0813, C0814, C0821, C0836, C0837, C0848, C0853, C0854, C0864, C0865, C0867, C0872, C0874, C0885, C0887, C0888, C0914, C0915, C0942, C1509, C1510, C3113, C3114, C3239, C3311, C3312, C3319, C3437, C3438 | |||||||
LDRA tool suite |
| 48 D, 63 D, 84 D, 113 D, 5 Q, 64 S, 65 S, 100 S, 109 S, 156 S, 296 S, 324 S, 335 S, 336 S, 339 S, 412 S, 427 S, 465 S, 482 S, 497 S, 545 S, 587 S, 608 S, 642 S, 62 X, 63 X | Partially implemented | ||||||
Parasoft C/C++test |
| CERT_C-MSC15-a | Evaluation of constant unsigned integer expressions should not lead to wrap-around | ||||||
Polyspace Bug Finder |
| Checks for undefined behavior (rec. partially covered) | |||||||
PVS-Studio |
| V772 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 6, "C Language Issues" (Arithmetic Boundary Conditions, pp. 211-223)
\[[Seacord 05|AA. C References#Seacord 05]\] Chapter 5, "Integers" |
Related Guidelines
SEI CERT C++ Coding Standard | VOID MSC15-CPP. Do not depend on undefined behavior |
ISO/IEC TR 24772 | Unspecified Behaviour [BQF] Undefined Behaviour [EWF] Implementation-Defined Behaviour [FAB] |
Bibliography
[ISO/IEC 9899:2011] | Subclause 3.4.3, "Undefined Behavior" Subclause 4, "Conformance" Subclause J.2, "Undefined Behavior" |
[Seacord 2013] | Chapter 5, "Integer Security" |
...
MSC14-A. Do not introduce unnecessary platform dependencies 14. Miscellaneous (MSC)