A segmentation fault means a program tried to access memory it wasn’t allowed to, and the operating system stepped in to prevent a crash.

Common Causes and Fixes

  1. Dangling Pointers/Use-After-Free: A program is trying to use a pointer to memory that has already been freed. This is a classic C/C++ bug.

    • Diagnosis: Run the program with valgrind --leak-check=full --show-leak-kinds=all. Valgrind is a dynamic analysis tool that detects memory errors. Look for "Invalid read" or "Invalid free" errors, which often point to use-after-free issues.
    • Fix: Review the code around the reported memory access. Ensure that any pointer is valid and points to allocated memory before dereferencing it. If a pointer is freed, set it to NULL immediately afterward to prevent accidental reuse.
    • Why it works: Valgrind tracks memory allocations and deallocations. By flagging accesses to freed memory, it highlights precisely where the program violates memory safety rules. Setting pointers to NULL after freeing makes subsequent attempts to use them result in a predictable NULL pointer dereference, which is easier to debug than a wild memory access.
  2. Buffer Overflow/Underflow: Writing data beyond the bounds of an allocated buffer. This can corrupt adjacent memory or overwrite control structures, leading to a crash when that corrupted data is later used.

    • Diagnosis: Again, valgrind is your best friend. Look for "Invalid write" errors originating from a write operation that exceeds the buffer’s allocated size.
    • Fix: Implement bounds checking for all buffer operations. Use safer functions like strncpy instead of strcpy, and snprintf instead of sprintf. Ensure the destination buffer is large enough for the data being copied, or truncate the data if necessary.
    • Why it works: valgrind detects writes that go outside the allocated memory regions. By using safer, size-aware functions and ensuring sufficient buffer space, you prevent the program from corrupting memory it doesn’t own.
  3. Stack Overflow: The program has exhausted the available stack space, typically due to excessively deep recursion or very large local variables.

    • Diagnosis: Check ulimit -s. This shows the current stack size limit in kilobytes. If the program is crashing deep in a recursive function, it’s a strong indicator. You can also use gdb and examine the call stack (bt command) for an unusually large number of frames.
    • Fix: Increase the stack size limit using ulimit -s unlimited (for the current session) or by modifying /etc/security/limits.conf. For recursive functions, refactor them to use iteration or tail-call optimization if possible. For large local variables, consider allocating them on the heap instead.
    • Why it works: Increasing the stack limit provides more memory for function call frames. Refactoring recursion or moving large data to the heap reduces the demand on the stack.
  4. Null Pointer Dereference: Attempting to access memory through a pointer that is NULL. This is a specific case of invalid memory access.

    • Diagnosis: gdb <your_program>. When the segmentation fault occurs, gdb will stop. Use the bt command to see the call stack. The frame where the fault occurred will often show a NULL pointer being dereferenced. The error message in gdb might be "Cannot access memory at address 0x0".
    • Fix: Add checks before dereferencing pointers to ensure they are not NULL. For example, if (ptr != NULL) { *ptr = value; }.
    • Why it works: The NULL pointer has a defined address (usually 0), but it’s not valid for general memory access. Explicitly checking for NULL prevents the program from attempting this illegal operation.
  5. Corrupted Pointers/Data Structures: Memory corruption from other errors (like buffer overflows) can damage pointers or critical data structures, leading to a segfault later when these corrupted items are used.

    • Diagnosis: This is harder and often requires a combination of valgrind (to catch the initial corruption) and gdb (to trace the consequence). If valgrind shows memory corruption far from where the segfault occurs, it’s a clue.
    • Fix: Fix the root cause of the memory corruption, which is often a buffer overflow or use-after-free elsewhere in the program. Thoroughly review code that writes to memory, especially around array boundaries and data structure manipulation.
    • Why it works: By identifying and fixing the initial memory corruption event, you prevent the subsequent, seemingly unrelated, segfault that occurs when the corrupted data is finally processed.
  6. Incorrect Use of Libraries/System Calls: Passing invalid arguments to library functions or system calls, or misinterpreting their return values, can lead to memory corruption or segmentation faults.

    • Diagnosis: Consult the documentation for the library function or system call that is being called in the stack trace. Pay close attention to argument types, valid ranges, and expected return values (especially error codes like -1 or NULL).
    • Fix: Correct the arguments being passed according to the library’s or system’s specifications. Ensure error conditions are properly handled. For example, if a malloc call returns NULL, the program should not attempt to use the returned pointer.
    • Why it works: Libraries and system calls often perform internal memory operations. Providing them with incorrect inputs can cause them to misbehave, leading to memory access violations. Adhering to their contracts ensures they operate safely.

After fixing these, you might hit a "Bus error" if the memory access was not only invalid but also misaligned with the processor’s requirements.

Want structured learning?

Take the full Linux & Systems Programming course →