Skip to content

C++ Segmentation Fault Fix

DodaTech Updated 2026-06-24 4 min read

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

The Problem

Your C++ program crashes with Segmentation fault (core dumped):

$ ./myprogram
Segmentation fault (core dumped)

A segfault occurs when the program tries to access memory it does not have permission to access. This is always a bug in the code -- dereferencing a null pointer, accessing freed memory, or writing past the end of an array.

Quick Fix

Step 1: Compile with debug symbols and address sanitizer

g++ -g -fsanitize=address -o myprogram myprogram.cpp
./myprogram

AddressSanitizer (ASan) gives a precise report:

==12345==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x55d8b7c3c123 bp 0x7ffc4a2b3f00 sp 0x7ffc4a2b3ee0 T0)
    #0 0x55d8b7c3c123 in main /home/user/myprogram.cpp:5

Step 2: Check for null pointer dereference

WRONG -- using a pointer without checking:

int* ptr = nullptr;
*ptr = 42;  // segmentation fault

RIGHT -- always check before dereferencing:

int* ptr = getValue();
if (ptr != nullptr) {
    *ptr = 42;
} else {
    std::cerr << "Error: ptr is null\n";
}

Step 3: Check array bounds

WRONG -- writing past the end of an array:

int arr[10];
for (int i = 0; i <= 10; i++) {  // i goes to 10, but valid indices are 0-9
    arr[i] = i;
}

RIGHT -- use correct bounds:

int arr[10];
for (int i = 0; i < 10; i++) {
    arr[i] = i;
}

Or use std::array or std::vector with .at() for bounds checking:

std::vector<int> vec(10);
for (int i = 0; i < vec.size(); i++) {
    vec.at(i) = i;  // throws std::out_of_range if i >= vec.size()
}

Step 4: Check for dangling pointers

WRONG -- using memory after it is freed:

int* ptr = new int(42);
delete ptr;
*ptr = 100;  // undefined behavior, likely segfault

RIGHT -- set pointer to nullptr after delete:

int* ptr = new int(42);
delete ptr;
ptr = nullptr;

// Or use smart pointers
std::unique_ptr<int> ptr = std::make_unique<int>(42);
// ptr is automatically freed when it goes out of scope

Step 5: Check for stack overflow

Deep recursion without a base case causes stack overflow:

WRONG -- infinite recursion:

int factorial(int n) {
    return n * factorial(n - 1);  // no base case, infinite recursion
}

RIGHT -- add a base case:

int factorial(int n) {
    if (n <= 1) return 1;  // base case
    return n * factorial(n - 1);
}

Or convert to iteration for very deep calls.

Step 6: Use Valgrind for detailed analysis

g++ -g -o myprogram myprogram.cpp
valgrind --leak-check=full ./myprogram

Valgrind reports invalid memory accesses, use-after-free, and memory leaks:

==12345== Invalid write of size 4
==12345==    at 0x109123: main (myprogram.cpp:5)
==12345==  Address 0x0 is not stack'd, not malloc'd or (recently) free'd

Use DodaTech's Debug Inspector to analyze core dumps and locate the exact line of the segfault without rebuilding.

Prevention

  • Initialize all pointers to nullptr or a valid address.
  • Use std::unique_ptr and std::shared_ptr instead of raw pointers.
  • Use std::vector::at() instead of operator[] for bounds checking.
  • Compile with -Wall -Wextra -fsanitize=address during development.
  • Run Valgrind or ASan in CI/CD to catch memory errors before release.
  • Enable core dumps with ulimit -c unlimited for post-mortem analysis.

Common Mistakes with segfault

  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

### How do I read a core dump to find the crash location?

Run gdb ./myprogram core. Then type bt (backtrace) to see the call stack at the crash point. Use frame N to jump to each frame and list to see the source code.

What is the difference between SIGSEGV and SIGABRT?

SIGSEGV (signal 11) is a segmentation fault -- invalid memory access. SIGABRT (signal 6) is an abort, triggered by assert() failures, std::terminate(), or abort() calls. Both usually indicate bugs, but SIGABRT is intentional.

Why does my program segfault only in release mode?

Release mode removes debug symbols and disables optimization barriers. The compiler may reorder instructions, and variables may be optimized out. Run ASan with -g -fsanitize=address even in release builds to catch these issues.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro