Fix: Segmentation fault (core dumped) in Linux / C / C++
Quick Answer
How to fix the 'Segmentation fault (core dumped)' error in Linux, covering null pointer dereference, buffer overflow, use-after-free, stack overflow, and debugging with GDB, Valgrind, and AddressSanitizer.
The Error
You run a compiled program and it crashes immediately with:
Segmentation fault (core dumped)Or you see the shorter variant:
Segmentation faultIf you’re running a Python script that uses C extensions, you might see:
$ python my_script.py
Segmentation fault (core dumped)The program terminates, and if core dumps are enabled, the kernel writes a core file to disk. Either way, nothing useful appears on screen — just that one cryptic line.
This error means your program tried to access a memory address it is not allowed to touch. The operating system kills it with signal 11 (SIGSEGV) to prevent damage.
Why This Happens
A segmentation fault occurs when a process attempts to read from or write to a memory address that the operating system has not mapped to it. The CPU’s memory management unit (MMU) detects the illegal access and raises a hardware exception. Linux translates this into SIGSEGV, which terminates the process by default.
The most common root causes are:
- Null pointer dereference — accessing memory through a pointer that is
NULL(address0x0). - Buffer overflow — writing past the end of an array or buffer, corrupting adjacent memory or hitting an unmapped page.
- Use-after-free — accessing memory that has already been freed with
free()ordelete. - Stack overflow — infinite or extremely deep recursion exhausts the stack, and the next function call writes beyond the stack guard page. If you hit recursive depth issues in Python specifically, see the guide on fixing Python RecursionError.
- Writing to read-only memory — modifying a string literal or a
const-qualified region that the linker placed in a read-only segment. - Misaligned access — on some architectures, accessing data at an address that is not properly aligned for the data type.
- Dangling pointers — using a pointer to a local variable after the function that owned it has returned.
Understanding which of these caused your crash is the key to fixing it. The sections below walk through each cause and its fix, plus the debugging tools that pinpoint the exact line.
Fix 1: Enable Core Dumps and Analyze Them
By default, many Linux distributions disable core dumps or limit their size. Without a core file, you lose the snapshot of your program’s state at the moment of the crash.
Enable core dumps for the current shell session:
ulimit -c unlimitedThen reproduce the crash. A file named core or core.<pid> appears in the current directory (or wherever your system is configured to write cores).
Note: Some systems redirect core dumps via /proc/sys/kernel/core_pattern. Check it:
cat /proc/sys/kernel/core_patternIf it shows a path like |/usr/lib/systemd/systemd-coredump, the core is managed by systemd. List recent cores with:
coredumpctl listAnd debug the latest one with:
coredumpctl debugAnalyze the Core File with GDB
If you have a traditional core file, load it into GDB:
gdb ./your_program coreGDB drops you at the exact instruction that caused the fault. Run bt (backtrace) to see the full call stack:
(gdb) bt
#0 0x0000555555555149 in process_data (ptr=0x0) at main.c:12
#1 0x00005555555551a2 in main () at main.c:25This tells you the crash happened at main.c:12 inside process_data, and the pointer ptr was 0x0 — a null pointer dereference.
Pro Tip: Compile your program with debug symbols (-g flag) before reproducing the crash. Without symbols, GDB shows raw addresses instead of function names and line numbers. Use gcc -g -o your_program your_program.c or add -g to your CFLAGS/CXXFLAGS in your build system.
Key GDB Commands for Segfault Debugging
| Command | What It Does |
|---|---|
bt | Full backtrace |
bt full | Backtrace with local variable values |
frame N | Switch to stack frame N |
print var | Print a variable’s value |
info registers | Show CPU register values |
x/10x $rsp | Examine 10 hex words at the stack pointer |
list | Show source code around the crash point |
Fix 2: Null Pointer Dereference
This is the single most common cause of segfaults. It happens when you dereference a pointer that is NULL:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *data = NULL;
printf("%c\n", data[0]); // SIGSEGV: dereferencing NULL
return 0;
}How to Fix It
Add null checks before every pointer dereference, especially after functions that can return NULL:
char *data = get_data();
if (data == NULL) {
fprintf(stderr, "Error: get_data() returned NULL\n");
return 1;
}
printf("%c\n", data[0]); // SafeCommon functions that return NULL on failure:
malloc(),calloc(),realloc()fopen()getenv()strstr(),strchr()- Any function documented as returning
NULLon error
Common Mistake: Assuming malloc() never fails. On systems with memory overcommit (most Linux desktops), malloc() rarely returns NULL — it returns a pointer, and the kernel kills the process later when physical memory runs out (the OOM killer). But on embedded systems, containers with memory limits, or when allocating very large blocks, malloc() absolutely can return NULL. Always check. If you’re running into OOM kills in containers, see Docker Exited (137) OOMKilled.
Fix 3: Buffer Overflow
Writing beyond the bounds of an array corrupts memory. If you’re lucky, it hits an unmapped page and you get an immediate segfault. If you’re unlucky, it silently corrupts other data and crashes later in an unrelated function.
#include <string.h>
int main() {
char buffer[10];
strcpy(buffer, "This string is way too long for the buffer");
// Writes 44 bytes into a 10-byte buffer → stack corruption → segfault
return 0;
}How to Fix It
Use size-bounded functions instead of their unbounded counterparts:
| Dangerous | Safe Alternative |
|---|---|
strcpy() | strncpy() or snprintf() |
strcat() | strncat() |
sprintf() | snprintf() |
gets() | fgets() |
scanf("%s", buf) | scanf("%9s", buf) (with width specifier) |
Fixed version:
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10];
snprintf(buffer, sizeof(buffer), "This string is way too long for the buffer");
// Truncates safely to 9 chars + null terminator
printf("%s\n", buffer);
return 0;
}For dynamic data, calculate the required size and allocate accordingly:
const char *input = get_user_input();
size_t len = strlen(input);
char *buffer = malloc(len + 1);
if (buffer == NULL) {
perror("malloc");
return 1;
}
memcpy(buffer, input, len + 1);Detect Buffer Overflows with AddressSanitizer
Compile with AddressSanitizer (ASan) to catch buffer overflows at runtime:
gcc -g -fsanitize=address -o your_program your_program.c
./your_programASan prints a detailed report showing exactly where the overflow happened:
==12345==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd12345678
WRITE of size 44 at 0x7ffd12345678 thread T0
#0 0x555555555123 in main /home/user/main.c:5ASan is available in GCC (4.8+) and Clang (3.1+). It adds ~2x runtime overhead, so use it during development and testing, not in production.
Fix 4: Use-After-Free
Accessing memory after calling free() is undefined behavior. The memory may have been returned to the OS (segfault) or reallocated for something else (silent corruption):
#include <stdlib.h>
#include <stdio.h>
int main() {
int *nums = malloc(5 * sizeof(int));
nums[0] = 42;
free(nums);
printf("%d\n", nums[0]); // Use-after-free → undefined behavior / segfault
return 0;
}How to Fix It
Set pointers to NULL immediately after freeing them. This turns a silent use-after-free into an obvious null pointer dereference, which is easier to debug:
free(nums);
nums = NULL; // Any later access through nums now crashes immediately at address 0x0For more structural fixes:
- Clarify ownership. Decide which part of your code “owns” each allocation and is responsible for freeing it. Document this in comments.
- Avoid returning pointers to freed memory. If a function frees a struct, make sure no other code holds a reference to it.
- Use Valgrind to detect use-after-free errors automatically (covered below).
In C++, prefer smart pointers (std::unique_ptr, std::shared_ptr) over raw new/delete. They free memory automatically when it goes out of scope and prevent most use-after-free bugs.
Fix 5: Stack Overflow from Deep Recursion
Every function call pushes a stack frame. If recursion goes too deep, the stack grows past its limit (typically 8 MB on Linux) and hits the guard page:
#include <stdio.h>
void recurse(int n) {
int large_array[1024]; // 4 KB per frame
printf("Depth: %d\n", n);
recurse(n + 1); // No base case → infinite recursion
}
int main() {
recurse(0);
return 0;
}How to Fix It
- Add a base case to your recursion:
void recurse(int n) {
if (n >= 1000) return; // Base case
int large_array[1024];
recurse(n + 1);
}- Convert to iteration if the recursion depth is unbounded:
void process_iteratively() {
for (int i = 0; i < max_depth; i++) {
// Do the work without recursive calls
}
}- Increase the stack size if your algorithm genuinely needs deep recursion:
ulimit -s 32768 # Set stack size to 32 MB (value is in KB)Or set it per-thread with pthread_attr_setstacksize().
Check the current stack size limit:
ulimit -sThis prints the limit in KB. The default is usually 8192 (8 MB).
If your program does heavy recursion in Python, the segfault might come from exceeding the C-level stack rather than Python’s recursion limit. See the Python RecursionError guide for details on that interaction.
Fix 6: Debug with Valgrind
Valgrind runs your program in a virtual environment that tracks every memory operation. It catches issues that AddressSanitizer misses and vice versa — they’re complementary tools.
valgrind --leak-check=full --track-origins=yes ./your_programValgrind reports errors like:
==54321== Invalid read of size 4
==54321== at 0x1091A2: process_data (main.c:18)
==54321== by 0x109210: main (main.c:31)
==54321== Address 0x4a3c050 is 0 bytes inside a block of size 20 free'd
==54321== at 0x483CA3F: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==54321== by 0x109198: cleanup (main.c:14)This tells you that main.c:18 reads from memory that was freed at main.c:14 — a use-after-free.
Key Valgrind Flags
| Flag | Purpose |
|---|---|
--leak-check=full | Report details of memory leaks |
--track-origins=yes | Show where uninitialized values came from |
--show-reachable=yes | Report memory that’s still reachable but not freed |
--log-file=valgrind.log | Write output to a file |
--suppressions=file.supp | Suppress known false positives |
Note: Valgrind slows your program by 10-50x. It’s a development tool, not a production monitor.
Valgrind vs. AddressSanitizer
| Feature | Valgrind | AddressSanitizer |
|---|---|---|
| Speed overhead | 10-50x | ~2x |
| Recompilation needed | No | Yes (-fsanitize=address) |
| Use-after-free | Yes | Yes |
| Buffer overflow | Yes | Yes (better for stack overflows) |
| Uninitialized reads | Yes (--track-origins) | No (use MemorySanitizer) |
| Memory leaks | Yes | Yes (LeakSanitizer, enabled by default with ASan) |
Use ASan during daily development (it’s fast). Use Valgrind for deeper analysis when ASan doesn’t catch the bug or when you can’t recompile.
Fix 7: Segfaults in Python C Extensions
Python itself is memory-safe, but C extensions (NumPy, Pandas, OpenCV, compiled Cython code) can segfault. When you see:
$ python my_script.py
Segmentation fault (core dumped)The crash is almost always in a C extension, not in your Python code.
How to Debug It
- Run Python under GDB:
gdb python
(gdb) run my_script.pyWhen it crashes, use bt to see which C function caused the fault.
- Use the
faulthandlermodule (Python 3.3+):
import faulthandler
faulthandler.enable()
# Your code hereOr enable it from the command line:
python -X faulthandler my_script.pyThis prints a Python traceback on segfault, showing which Python-level call triggered the crash.
- Common causes and fixes:
- Version mismatch: Your C extension was compiled against a different Python version or NumPy version. Fix: reinstall the package with
pip install --force-reinstall --no-cache-dir <package>. - Corrupted installation: Fix: create a fresh virtual environment and reinstall dependencies.
- Bug in the extension: Check the library’s GitHub issues for known segfaults. Update to the latest version.
- Thread safety: Some C extensions are not thread-safe. If you’re using
threading, try switching tomultiprocessingor adding locks.
Fix 8: Use AddressSanitizer for Comprehensive Detection
AddressSanitizer is a compiler-based tool that instruments your code to detect memory errors at runtime. It catches more than just the errors that cause immediate segfaults — it finds bugs that silently corrupt memory and would crash later.
What ASan Detects
- Stack buffer overflow
- Heap buffer overflow
- Global buffer overflow
- Use-after-free
- Use-after-return (with
ASAN_OPTIONS=detect_stack_use_after_return=1) - Double-free
- Memory leaks (via integrated LeakSanitizer)
How to Use It
Compile with ASan flags:
# GCC
gcc -g -fsanitize=address -fno-omit-frame-pointer -o program program.c
# Clang
clang -g -fsanitize=address -fno-omit-frame-pointer -o program program.c
# C++ (either compiler)
g++ -g -fsanitize=address -fno-omit-frame-pointer -o program program.cppThe -fno-omit-frame-pointer flag ensures ASan can produce accurate stack traces.
Run the program normally:
./programASan automatically intercepts memory operations and reports violations with full stack traces.
Tuning ASan Behavior
Control ASan via the ASAN_OPTIONS environment variable:
ASAN_OPTIONS=halt_on_error=0:detect_leaks=1:print_stats=1 ./programUseful options:
| Option | Effect |
|---|---|
halt_on_error=0 | Continue after first error (default: halt) |
detect_leaks=1 | Enable leak detection |
detect_stack_use_after_return=1 | Detect dangling stack references |
check_initialization_order=1 | Detect C++ static init order bugs |
Combine with Other Sanitizers
For even deeper analysis, use UndefinedBehaviorSanitizer alongside ASan:
gcc -g -fsanitize=address,undefined -fno-omit-frame-pointer -o program program.cThis catches integer overflow, null pointer dereference through different code paths, and other undefined behavior that might not trigger a segfault but indicates bugs.
Fix 9: Writing to Read-Only Memory
String literals in C are stored in a read-only memory segment. Modifying them causes a segfault:
int main() {
char *str = "hello"; // Points to read-only memory
str[0] = 'H'; // SIGSEGV: writing to read-only segment
return 0;
}How to Fix It
Use an array instead of a pointer to create a mutable copy:
int main() {
char str[] = "hello"; // Copies the string to the stack (mutable)
str[0] = 'H'; // Works fine
return 0;
}Or allocate on the heap:
#include <string.h>
#include <stdlib.h>
int main() {
char *str = strdup("hello"); // Heap-allocated mutable copy
if (str == NULL) return 1;
str[0] = 'H'; // Works fine
free(str);
return 0;
}In C++, use std::string to avoid this class of bugs entirely.
Fix 10: Check File Permissions and Missing Libraries
Sometimes the segfault has nothing to do with your code. It happens because:
- A shared library is missing or incompatible. Run
ldd ./your_programto check for missing dependencies. - A corrupted binary. Recompile from clean source.
- Insufficient memory. The process can’t allocate the memory it needs. Check with
dmesg | tailfor OOM messages. If you’re hitting memory limits in containers or services, see Docker OOMKilled or Java OutOfMemoryError for memory-related troubleshooting.
Check dmesg for kernel-level information about the crash:
dmesg | tail -20You’ll see something like:
[12345.678] program[9876]: segfault at 0 ip 00005555555551a2 sp 00007fffffffde10 error 6 in program[555555555000+1000]The at 0 tells you it was a null pointer dereference (address 0). The ip value is the instruction pointer — you can look it up with addr2line:
addr2line -e ./your_program 0x00005555555551a2This prints the source file and line number (if compiled with -g).
Fix 11: System-Level Fixes
Disable ASLR for Debugging
Address Space Layout Randomization (ASLR) makes memory addresses different on each run, which can make debugging harder. Temporarily disable it:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_spaceWarning: Re-enable ASLR after debugging. It is a security feature. Set it back with echo 2 | sudo tee /proc/sys/kernel/randomize_va_space.
Make Core Dumps Persistent
To enable core dumps permanently, not just for the current session:
Add to /etc/security/limits.conf:
* soft core unlimited
* hard core unlimitedSet the core dump pattern:
echo '/tmp/core.%e.%p.%t' | sudo tee /proc/sys/kernel/core_patternThis writes cores to /tmp/ with the executable name, PID, and timestamp.
If your program runs as a systemd service, note that systemd may manage core dumps separately. See the systemctl service failed guide for debugging services that crash with segfaults.
Check for Hardware Issues
Rarely, segfaults that appear random and irreproducible indicate faulty RAM. Run a memory test:
sudo memtest86+Or use the kernel’s built-in memory checker by adding memtest to your GRUB boot options.
If you’re seeing segfaults on a server, also check dmesg for MCE (Machine Check Exception) errors, which indicate hardware-level memory corruption.
Still Not Working?
If none of the fixes above resolve your segfault, try these less common approaches:
Check for ABI incompatibility. If you’re linking against pre-compiled libraries, make sure they were compiled for the same architecture (x86_64 vs. ARM) and with a compatible compiler version. Mismatched C++ ABIs between GCC versions are a classic source of mysterious segfaults.
Look for race conditions. Multi-threaded programs can segfault when two threads access the same data without synchronization. Use ThreadSanitizer (
-fsanitize=thread) to detect data races.Check your build system. Partial recompilation after changing struct layouts or function signatures can cause segfaults. Run
make clean && makeor equivalent to rebuild from scratch.Inspect environment variables. Some programs segfault when expected environment variables are missing or malformed. Check what the program expects. If you’re dealing with shell permission issues that affect how your program runs, see the bash permission denied guide.
Update your compiler and OS. Compiler bugs exist, though they’re rare. If you’re on an old GCC (4.x or early 5.x), try upgrading to a modern version. Also update your kernel — segfaults caused by kernel bugs in memory management do happen.
Try a different allocator. Replace the default
mallocwithjemallocortcmallocto see if the crash changes. If it does, the bug likely involves heap corruption. Set it withLD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 ./your_program.Run with Electric Fence.
libefencereplacesmallocwith a version that places each allocation at the end of a page. Any buffer overflow triggers an immediate segfault at the exact line, instead of corrupting memory silently:
sudo apt install electric-fence
LD_PRELOAD=/usr/lib/libefence.so ./your_program- Binary analysis with
objdump. If you don’t have source code, disassemble the binary to understand what instruction caused the fault:
objdump -d ./your_program | lessSearch for the instruction address from dmesg output to see the assembly context.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Python PermissionError: [Errno 13] Permission denied
How to fix Python PermissionError Errno 13 Permission denied when reading, writing, or executing files, covering file permissions, ownership, virtual environments, Windows locks, and SELinux.
Fix: Angular ExpressionChangedAfterItHasBeenCheckedError
How to fix ExpressionChangedAfterItHasBeenCheckedError in Angular caused by change detection timing issues, lifecycle hooks, async pipes, and parent-child data flow.
Fix: AWS Lambda Unable to import module / Runtime.ImportModuleError
How to fix the AWS Lambda Runtime.ImportModuleError and Unable to import module error caused by wrong handler paths, missing dependencies, layer issues, and packaging problems.
Fix: C# async deadlock — Task.Result and .Wait() hanging forever
How to fix the C# async/await deadlock caused by Task.Result and .Wait() blocking the synchronization context in ASP.NET, WPF, WinForms, and library code.