Diagnosing and Resolving Segmentation Faults (SIGSEGV) in C
A technical guide to diagnosing SIGSEGV in C. Learn how to use GDB and Valgrind to identify NULL pointers, buffer overflows, and use-after-free errors.
23 Jul 2025, 17:00 UTC

The Problem: Memory Access Violations
A Segmentation Fault (SIGSEGV) occurs when a C program attempts to access a memory location that it is not allowed to access, or attempts to access it in a way that is not permitted (e.g., writing to a read-only segment). Because C provides direct memory management, these crashes are often the result of pointer mismanagement or boundary errors.
Identifying the Root Cause
Not all crashes are caused by the same error. Use this table to match your observed behavior with the likely memory violation.
| Symptom | Likely Cause | Memory Region |
|---|---|---|
| Crash occurs immediately upon dereferencing a pointer | NULL pointer or uninitialized pointer | Address 0x0 or garbage address |
| Crash occurs during a loop or array iteration | Buffer overflow (out-of-bounds) | Heap or Stack |
Crash occurs during a free() or malloc() call |
Heap corruption or double-free | Heap Metadata |
| Crash occurs during deep recursion | Stack overflow | Stack Segment |
| Crash occurs after a pointer was previously freed | Use-after-free (Dangling pointer) | Deallocated Heap |
Step-by-Step Diagnostic Process
To resolve a SIGSEGV, you must move from observing the crash to identifying the specific line of code and the state of the pointer at that moment.
1. Compile with Debug Symbols
Standard compilation strips the mapping between machine code and your source lines. You must include debug symbols to make the crash location readable.
# Run this on your development machine
gcc -g -O0 main.c -o debug_build
Note: The -O0 flag disables optimization, preventing the compiler from reordering instructions or removing variables, which ensures the debugger points to the exact line of failure.
2. Isolate the Failure Point with GDB
Run the program inside the GNU Debugger (GDB) to capture the state of the program at the exact moment of the fault.
- Start the debugger:
gdb ./debug_build - Run the program:
run [arguments] - When the program crashes, generate a backtrace:
bt
The bt (backtrace) command reveals the call stack. Look for the highest frame that belongs to your source code to find the failing line.
3. Analyze Memory Access with Valgrind
Some memory errors (like writing one byte past an array) do not cause an immediate crash but corrupt memory that causes a crash later. Valgrind's Memcheck tool detects these "silent" errors.
# Run on Linux environment
valgrind --leak-check=full ./debug_build
Look for "Invalid write of size X" or "Invalid read of size X". These messages identify exactly where the boundary was crossed, even if the program didn't crash at that specific line.
Fixing Common Violations
Scenario: The NULL Pointer
If GDB shows a crash at a line like ptr->value = 10; and print ptr returns 0x0, you have a NULL pointer dereference.
Fix: Implement a guard clause before access.
if (ptr == NULL) {
fprintf(stderr, "Error: Pointer is null\n");
return ERROR_CODE;
}
Scenario: Buffer Overflow
If Valgrind reports an "Invalid write" inside a loop, you are likely accessing an index equal to or greater than the allocated size.
Example of a common error:
int *arr = malloc(10 * sizeof(int));
for (int i = 0; i <= 10; i++) { // Error: should be i < 10
arr[i] = 0;
}
Fix: Ensure loop boundaries are strictly less than the allocated length.
Scenario: Use-After-Free
This occurs when a pointer is used after free() has been called on it.
Fix: Set pointers to NULL immediately after freeing them. This converts a hard-to-find "use-after-free" bug into a predictable NULL pointer crash that is easier to debug.
free(ptr);
ptr = NULL;
Verification and Limitations
To verify the fix, run the program through Valgrind again. A successful fix is not just a program that doesn't crash, but one that reports "All heap blocks were freed -- no leaks are possible" and "0 errors from 0 contexts".
Limitations: Be aware of "Heisenbugs." Adding printf statements can change the memory layout of the stack or heap, potentially hiding a segmentation fault during debugging only to have it reappear in production. Always rely on GDB and Valgrind rather than print-debugging for memory issues.
Escalation Criteria
If the following conditions are met, the issue may be beyond simple pointer mismanagement:
- The crash occurs inside a third-party compiled library where source code is unavailable.
- The crash is non-deterministic and occurs only under high concurrency (suggesting a Race Condition).
- The crash occurs despite Valgrind reporting zero memory errors (suggesting a hardware failure or kernel-level issue).
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.