Debugging Fundamentals
Debugging C is an art. Unlike managed languages where the runtime catches null references and out-of-bounds accesses with clear exceptions, C will silently corrupt memory, produce wrong results, or crash with nothing but “Segmentation fault (core dumped).” The bug that crashes your program at line 500 may have been caused by a buffer overflow at line 50. This chapter arms you with the tools and techniques to systematically hunt down even the most devious bugs.GDB Essentials
Starting GDB
Basic Commands
Advanced GDB
GDB Init File
Core Dumps
Enabling Core Dumps
Analyzing Core Dumps
Triggering Core Dumps
Memory Debugging
Valgrind
Valgrind runs your program on a synthetic CPU, intercepting every memory access. This gives it superpowers (detecting reads of uninitialized memory, off-by-one errors, leaks) but makes your program 10-50x slower. Always test with Valgrind before shipping, but do not use it for performance benchmarks.Understanding Valgrind Output
AddressSanitizer
AddressSanitizer (ASan) is a compile-time instrumentation tool that catches memory errors at runtime with only 2x slowdown (much faster than Valgrind). It detects heap/stack/global buffer overflows, use-after-free, use-after-return, double-free, and memory leaks. In practice, run your test suite with ASan enabled as part of CI — it catches bugs that would take days to track down with GDB.Common Memory Errors
These are the seven deadly sins of C memory management. Every one of them is undefined behavior — meaning the program might crash, produce wrong results, appear to work fine, or even format your hard drive (in theory). The terrifying part: “appears to work fine” is the most common outcome in development, and “crashes in production” is when you find out.Debugging Patterns
Printf Debugging (But Better)
Assertions
Memory Debugging Wrapper
Tracing System Calls
ltrace (Library Calls)
Debugging Crashes Systematically
Reproduce Consistently
Find the minimal input/steps to trigger the crash. Randomness = harder debugging.
Find the Root Cause
The crash site is almost never the bug itself. A segfault in
free() usually means someone corrupted the heap much earlier. A wrong value in a calculation often traces back to an uninitialized variable set 50 lines ago. Work backwards from the crash: when did the state first become invalid? Use watchpoints in GDB (watch variable) to catch the exact moment a value changes unexpectedly.Exercises
GDB Mastery
Write a program with a linked list. Use GDB to traverse the list, print node values, and find a bug you intentionally introduce.
Core Dump Analysis
Write a program that crashes. Generate a core dump and analyze it to find the crash location.
Memory Bug Hunt
Write a program with at least 3 different memory bugs. Use Valgrind and AddressSanitizer to find them all.
Next Up
Pointers Deep Dive
Master the heart of C programming