What is Undefined behavior?

Behavior for which the C or C++ standard imposes no requirements. Examples are signed integer overflow, reading or writing outside an array, dereferencing a null pointer, using freed memory and left-shifting a negative value. A compiler may optimize on the assumption that a correct program never has undefined behavior, so such code may happen to work as expected, or may give unexpected results, for example a check disappearing under some optimization settings. It is distinguished from implementation-defined behavior, which the implementation chooses and documents.

Japanese name: 未定義動作

Undefined behavior appears in 11 practice questions across 3 topics, including C Programming Basics, Compilers, Multicore & Synchronization.

Field: C Programming Basics

Typical examples

Examples include overflow in signed integer arithmetic (such as INT_MAX + 1), reading or writing outside an array, using the value of an uninitialized automatic variable, reading or writing through a null or dangling pointer, freeing the same memory twice, integer division by 0, and shifting by the type width or more or left-shifting a negative value. Overflow of unsigned integers is not undefined behavior; it is defined to wrap around modulo a power of 2.

Relation to compiler optimization

Because the compiler may assume that undefined behavior never happens, it may treat x + 1 > x as always true, or delete a p == NULL check that comes after *p has been read. So a program that worked as expected at -O0 can stop working just by switching to -O2 or upgrading the compiler. This is not a compiler bug; the cause is that the program breaks an assumption of the standard.

Finding and preventing it

With gcc or clang, -fsanitize=undefined (UBSan) detects signed integer overflow and similar errors at run time, and -fsanitize=address (ASan) detects out-of-bounds accesses and use after free. Warnings from -Wall and -Wextra, static analysis tools and coding rules such as MISRA C also help reduce undefined behavior.

Try it: questions about Undefined behavior

Which of the following describes undefined behavior as defined by the C standard?

  1. ABehavior the standard places no requirements on; the compiler may optimize assuming it never happens, so results can be unexpected
  2. BBehavior for which each implementation decides the result and is required to document it
  3. CBehavior that is always detected at run time, printing an error message and stopping the program
Show answer and explanation

Answer: A. Behavior the standard places no requirements on; the compiler may optimize assuming it never happens, so results can be unexpected

Undefined behavior is behavior on which the standard imposes no requirements, such as signed integer overflow, out-of-bounds array access, null pointer dereference and use after free. It may happen to work as expected, but because the compiler may optimize on the assumption that it "does not happen in a correct program", merely changing optimization settings or the compiler version can change the result. In contrast, things such as the size of int and whether char is signed, which the implementation decides and must document, are called implementation-defined behavior. With gcc and clang, -fsanitize=undefined detects some undefined behavior at run time.

int and unsigned int are 32 bits. Which of the following is undefined behavior according to the C standard?

  1. AAdding 1 to an unsigned int variable whose value is the maximum 4294967295
  2. BShifting a negative int value right by 1 bit with >>
  3. CAdding 1 to an int variable whose value is the maximum 2147483647
Show answer and explanation

Answer: C. Adding 1 to an int variable whose value is the maximum 2147483647

A signed integer operation whose result exceeds the representable range, such as 2147483647 + 1 in int, is undefined behavior. Unsigned integer arithmetic is defined to wrap modulo 2³², so 4294967295 + 1 gives 0 and is not undefined behavior. Right-shifting a negative value is implementation-defined behavior, where the implementation decides whether it is an arithmetic or a logical shift; gcc uses an arithmetic shift. On the other hand, left-shifting a negative value is undefined behavior.

FAQ

What is the difference between undefined behavior and implementation-defined behavior?

Implementation-defined behavior, such as the size of int, whether char is signed, or the result of right-shifting a negative value, is behavior for which the implementation chooses one option and documents it. Undefined behavior is behavior on which the standard imposes no requirements, and the result may differ from case to case even with the same implementation. Portable programs make any reliance on implementation-defined behavior explicit and avoid undefined behavior altogether.

If code with undefined behavior works, is it a problem?

Yes. Even if it happens to work as expected in the current environment, a change in optimization settings, the compiler version or the surrounding code can give a different result. From a security point of view as well, undefined behavior such as out-of-bounds writes can be exploited by attackers.

Undefined behavior in the explanations

Questions that mention Undefined behavior (11)

  1. In C, signed integer overflow is undefined behavior. Under this rule, which code might an optimizing compiler generate for the function above?
  2. Which of the following describes undefined behavior as defined by the C standard?
  3. int and unsigned int are 32 bits. Which of the following is undefined behavior according to the C standard?
  4. Which describes a data race?
  5. uint8_t is an 8-bit unsigned integer type. Which of the following is the output when the code above, which increments x ten times, is executed?
  6. int is 32 bits (maximum 2147483647). Which of the following is the largest n for which the function fact(n) above returns the factorial of n correctly, without overflow?
  7. Which of the following is true about the pointer returned by the function make above?
  8. In C, which of the following is the most appropriate reason it is recommended to write p = NULL; right after free(p);?
  9. In C, which of the following describes what happens when a null pointer is dereferenced (*p is read while p is NULL)?
  10. Which of the following is the output when the code above, which uses the macro SQUARE defined with #define, is executed?
  11. When the function above is compiled with gcc with optimization enabled, the check if (p == NULL) may be removed. Which of the following is the reason?

Books on C Programming Basics Ad

As an Amazon Associate I earn from qualifying purchases.

Related terms

Pointer Modulo operation Variable Array Arithmetic shift Data race Stack Dangling pointer Dynamic memory allocation Heap memory

Back to the glossary