This content originally appeared on Level Up Coding – Medium and was authored by Wadix Technologies

1.Introduction:
When writing firmware in C on Linux, you’ve probably run into a brutal crash with that dreaded message:
“Segmentation fault (core dumped)”
It often happens without warning — and gives you almost no hint about what went wrong. That’s when the hunt begins: digging through your code, adding printfs, and guessing where the problem might be.
To deal with segmentation faults effectively, we need to understand why they happen, how to avoid them, and — most importantly — how to debug them when they do.
2. What Is a Segmentation Fault?
by definition the term segmentation fault, we usually get the same short answer:
“You tried to access a memory location you’re not allowed to.”
But what does that really mean?
To understand this, we need to talk about how memory works in Linux. All user-space programs run in a virtual memory space. Each process thinks it has the entire memory to itself, but in reality, the operating system is managing access behind the scenes.
The OS assigns each process its own logical layout with segments like the text (code), data, heap, and stack. But when it comes to actual memory mapping, the OS works in pages — fixed-size blocks (typically 4 KB) used by the Memory Management Unit (MMU) to translate virtual addresses into physical addresses.
Every time a process accesses memory, the CPU checks if the virtual address has a valid translation — first by looking in the Translation Lookaside Buffer (TLB). If it’s not cached there, it walks the page table, which holds the mappings between virtual pages and physical frames.
If the CPU can’t find a valid translation — meaning the address isn’t mapped or accessible by the process — it raises an exception known as a page fault. When this page fault can’t be resolved (for example, because the address truly doesn’t belong to the process), the kernel steps in and kills the process. The result? A segmentation fault.
In short, a segmentation fault happens when a process tries to touch memory that doesn’t exist in its address space, or that it’s not allowed to access.

3. Common Causes (Examples) of Segmentation Faults
Segmentation faults can happen for a variety of reasons, but most of the time they come down to improper memory access
Dereferencing a NULL pointer
Trying to access memory through a pointer that hasn’t been initialized or was explicitly set to NULL.
dangling pointer
Using a pointer after the memory it pointed to has already been freed (use-after-free).
Buffer overflows
Writing or reading beyond the boundaries of an array or buffer.
Stack overflow
Caused by deep or infinite recursion, or allocating too much data on the stack.
Uninitialized or wild pointers
Using a pointer that was never set to a valid memory address.
Incorrect type casting
Casting pointers improperly, leading to access of invalid memory regions.
4. How to Debug a Segmentation Fault
When a segmentation fault occurs, the first step is to identify where and why it happened. Fortunately, Linux provides several powerful tools that can help — even when the error message itself gives you no clue.
· GDB (GNU Debugger)
gdb ./program
(gdb) run
(on crash)
(gdb) bt # Show backtrace
· Valgrind
detect invalid memory access, use-after-free, and memory leaks
· Core dump file
Enable core dumps using ulimit -c unlimited. When your program crashes, a core file is generated that you can analyze later with gdb:
gdb ./program core
But sometimes you’re working in an environment where you don’t have access to gdb or Valgrind — for example, on an embedded Linux board or a minimal system. In these cases, you need another way to capture useful information
You can map a custom signal handler for SIGSEGV that will print a stack trace when your program crashes. This requires <execinfo.h> and works without external tools.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <execinfo.h>
#include <unistd.h>
void segfault_handler(int sig)
{
void *array[20];
size_t size;
const char msg[] = "Segmentation fault caught!\n";
write(STDERR_FILENO, msg, sizeof(msg));
size = backtrace(array, 20);
backtrace_symbols_fd(array, size, STDERR_FILENO);
/* Exit safely*/
_exit(EXIT_FAILURE);
}
void trigger_seg_fault(void *ptr)
{
int *myptr = (int *)ptr;
printf("Executing risky operation…\n");
myptr[2] = 0;
}
int main()
{
struct sigaction act =
{
.sa_handler = segfault_handler,
.sa_flags = 0,
};
sigemptyset(&act.sa_mask);
if (sigaction(SIGSEGV, &act, NULL))
{
perror("sigaction");
exit(EXIT_FAILURE);
}
printf("trigger_seg_fault ..\n");
trigger_seg_fault(NULL );
return 0;
}
to make your crash trace meaningful, you need to compile your program with debug symbols. backtrace_symbols() to show file names, function names, and line numbers.
gcc -g3 -rdynamic -o segfault_debug main.c
When a segmentation fault occurs and your custom handler prints a call stack:

You can also dump the entire binary to analyze its layout or disassembly using objdump:
objdump -d ./segfault_debug > dump.txt
Then search for the address from your crash log inside dump.txt to see the exact instruction and function context
5.conclusion:
Segmentation faults are one of the most common and frustrating errors — but they don’t have to be mysterious. With the right tools and techniques, like gdb, Valgrind, or even a custom signal handler, you can trace the fault back to its source and fix it with confidence. Whether you’re debugging on a full Linux system or a minimal embedded board, understanding how memory works and how to investigate crashes will save you time and headaches.
If you enjoyed this article, please make sure to Subscribe, Clap, Comment and Check out our online courses today!
Segmentation Faults in Linux: What They Are and How to Debug Them was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding – Medium and was authored by Wadix Technologies