Skip to content

C++ Undefined Behavior Fix

DodaTech Updated 2026-06-24 4 min read

In this tutorial, you'll learn about C++ Undefined Behavior Fix. We cover key concepts, practical examples, and best practices.

The Problem

Your C++ program produces different results on different compilers, crashes only in release mode, or works correctly every time you run it except in production:

$ ./myprogram
# sometimes works, sometimes crashes
# different output on GCC vs Clang
# crashed in release but not debug

These symptoms point to undefined behavior (UB). The C++ standard allows the compiler to assume UB never happens, so the compiler can generate any code when UB occurs -- including code that appears to work, crashes, or silently corrupts data.

Quick Fix

Step 1: Compile with UndefinedBehaviorSanitizer

g++ -g -fsanitize=undefined -o myprogram myprogram.cpp
./myprogram
myprogram.cpp:5:20: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'

UBSan catches most common UB at runtime with a precise location.

Step 2: Initialize all variables

WRONG -- uninitialized variable:

int count;
if (someCondition) {
    count = 10;
}
std::cout << count;  // UB if someCondition was false

RIGHT -- always initialize:

int count = 0;
if (someCondition) {
    count = 10;
}
std::cout << count;  // safe

Step 3: Fix signed integer overflow

WRONG -- signed overflow is UB:

int max = 2147483647;
int result = max + 1;  // undefined behavior

RIGHT -- use unsigned types or check bounds:

int max = 2147483647;
if (max < INT_MAX) {
    int result = max + 1;  // safe
}

Or use int64_t for larger range:

int64_t max = 2147483647;
int64_t result = max + 1;  // no overflow for reasonable ranges

Step 4: Fix null pointer arithmetic

WRONG -- arithmetic on null pointer:

int* ptr = nullptr;
int* other = ptr + 5;  // UB: adding to null pointer

RIGHT -- only use valid pointers:

int arr[10];
int* ptr = arr;
int* other = ptr + 5;  // safe: within the array

Step 5: Fix strict aliasing violations

WRONG -- accessing an object through an incompatible pointer type:

float value = 3.14f;
int* ptr = reinterpret_cast<int*>(&value);
int bits = *ptr;  // UB: strict aliasing violation

RIGHT -- use memcpy or std::bit_cast (C++20):

float value = 3.14f;
int bits;
std::memcpy(&bits, &value, sizeof(value));  // safe

Or in C++20:

float value = 3.14f;
int bits = std::bit_cast<int>(value);  // safe and explicit

Step 6: Fix data races with proper synchronization

WRONG -- multiple threads writing without synchronization:

int counter = 0;

// In two threads:
counter++;  // UB: data race on counter

RIGHT -- use atomic operations:

std::atomic<int> counter = 0;

// In two threads:
counter++;  // safe: atomic increment

Or use a mutex:

int counter = 0;
std::mutex mtx;

// In two threads:
{
    std::lock_guard<std::mutex> lock(mtx);
    counter++;  // safe: protected by mutex
}

Use DodaTech's Static Analyzer to scan your codebase for UB patterns before they reach production.

Prevention

  • Compile with -Wall -Wextra -fsanitize=undefined,address during development.
  • Initialize every variable at the point of declaration.
  • Enable all compiler warnings and treat them as errors (-Werror).
  • Use gsl::not_null for pointers that must never be null.
  • Run UBSan in CI/CD to catch UB on every commit.
  • Use std::atomic and mutexes for all shared mutable state between threads.

Common Mistakes with undefined behavior

  1. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  2. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
  3. Using head and tail instead of pattern matching, causing runtime errors on empty lists

These mistakes appear frequently in real-world CPP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why does undefined behavior work on my machine but crash on the server?

Different compilers, compiler versions, or optimization levels handle UB differently. Release builds (-O2/-O3) are especially aggressive at exploiting UB for optimization. Code that happens to work in debug mode may fail dramatically in release.

What is the most common source of UB in C++?

Uninitialized variables and signed integer overflow are the most common. Both are easy to miss and can produce hard-to-reproduce bugs. Compile with UBSan and -Wmaybe-uninitialized to catch them.

How do I permanently disable signed overflow UB in GCC?

Use -fwrapv to make signed integer overflow wrap around predictably (two's complement). This is not standard-compliant but is safer for legacy codebases. For new code, fix the overflows instead.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro