Unit 5.4 · about 3 h
30 / 324Debuggers, logs, traces and competing hypotheses
Editing before observing creates new bugs while the old one hides. A short hypothesis log plus one distinguishing observation usually beats an hour of guessing.
- measure
You can now
- Rank competing root-cause hypotheses and pick the observation that distinguishes them before editing code.
- Drive
pdb,logging,straceand sanitizer output to locate a defect with tool evidence. - Shrink a failure to a minimal reproducer and pin it with a regression test.
Covers
- Debugger, logs, traces and minimum distinguishing observations
- Competing hypotheses, evidence and root-cause notes
Study, in this order
4 steps
- Debugging and Profiling: the Debugging halfThe Missing Semester of Your CS Education
Debugging: Printf Debugging and Logging; Debuggers with the
gdbcommand list; Record-Replay Debugging withrrreverse commands; System Call Tracing withstraceflags; Memory Debugging with sanitizer compile flagsDepth · Skim Profiling, Timing through Benchmarking. That half belongs to a later section; stop at the Exercises under Debugging.
- Fast debugging methodologyThe Art of Debugging
Core principles: quick iterations with small payload, real versus random versus synthetic data; Atomic debug cycles; Finding the cause: editing the right file, bisecting revisions
- Debugging Python programsThe Art of Debugging
Choosing the right approach; Running the code you think you are running; Interactive debugging including
pdbattach and embed; Diagnosing hangs withpy-spy - Debugger and logging recipesStas' Python Cookbook - debugging and testing
Debugging: The interactive debugger command list; Printing, Logging and Output Control: the
loggingblock, prefer it overprintfor real programs
Focus on
- Write two or three competing hypotheses first, each with the single observation that would kill it. Run the cheapest distinguishing observation before changing code.
- Confirm you run the code you edit: check the module path for installed copies shadowing the repo. Every later observation misleads otherwise.
- Match the tool to the question:
breakpointfor state,loggingfor history,strace -f -e trace=filefor missing files,strace -f -p PIDfor a hang, AddressSanitizer for memory corruption,rr reverse-continuefor Heisenbugs. - On Python 3.14,
python -m pdb -p PIDattaches to a running process. Under Ubuntu's defaultptrace_scopeof 1 it fails on a process that is not its descendant (Failed to find the PyRuntime section) unless run withsudo;py-spy dumpneeds the same permission.
Reproduce closed-book
breakpoint, read the distinguishing variable, fix, and add the regression test. End state: the log shows each rejected hypothesis with its evidence, and the suite is green.Traps
- Debugging the wrong copy: an installed package shadows your edited repo file. Check the module path before trusting any observation.
- Trusting an observer that changes timing. Prints,
straceandrr's single-core recording all perturb a race; keep instrumentation cheap and in memory, and userr record --chaosto provoke the failing schedule. - Declaring victory without a regression test. The next refactor reintroduces the same defect silently.
Practice
Missing Semester merge-sort debugger exercise
Exercises under Debugging, item 1: implement the buggy merge sort, find the bug with a debugger and fix it
Keep a hypothesis log with at least two competing hypotheses before you set the first breakpoint.
Missing Semester sanitizer and strace exercises
Exercises under Debugging, items 3 and 4: the uaf.c AddressSanitizer report and the strace file listing
Compile with gcc -fsanitize=address -g as the lecture shows and quote the faulting line.
Self-test
-
Two hypotheses: wrong constant versus wrong index. What is one distinguishing observation?
Break at the indexing line and read the index and the constant. One read kills one hypothesis. -
A program hangs on startup with no output. Which tool first, and with what flags?
strace -f -p PID, or rerun it understrace -f. The last system call shows where it blocks, such as a read on a socket or pipe, a connect, or a futex wait. Add-e trace=fileto see missing files (ENOENT) on the way. -
Why convert prints to log statements after the fix?
Logs keep severity, destination and history for the next similar bug. Removed prints lose the evidence path; the lecture recommends this explicitly. -
rr records a passing run of a race bug. What now?
Record again until a failing run is captured:rrserializes scheduling, so intermittent races may need several attempts. Then replay deterministically with reverse debugging.
Completion criterion
Stop when
A seeded defect you have never seen takes under an hour from log entry to green regression test, with tool output quoted for every rejected hypothesis.
Mark passed, then open 5.5 Only mark this when you can do it without notes.Leads to
- 5.5 Shell streams, exit status, signals, processes and permissions Diagnose processes from the shell with streams, exit status, signals and
strace. - 5.6 Git history, merges, rebases, bisect and recovery Bisect the history once the log points at a recent change.
Comes after
- 3.6 Context managers, exceptions and deterministic cleanupRead tracebacks and chains as evidence before editing.
- 5.2 Property, metamorphic and differential testing with shrinkingFeed shrunk counterexamples into a hypothesis log as the first observation.
- 5.3 Regression tests, failure injection and flaky testsTurn the isolated flake or regression into a hypothesis log with tool evidence.
- 5.5 Shell streams, exit status, signals, processes and permissionsUse
straceand process state as debugger evidence for hangs and missing files. - 5.6 Git history, merges, rebases, bisect and recoveryBisect feeds the hypothesis log once it points at a recent change.
Resources for this unit
- The Missing Semester of Your CS Education Complete the 2026 lectures on the shell, command-line environment, development tools, debugging and profiling, Git, packaging and shipping code, and code quality. Apply every exercise to the same stage project.
- The Art of Debugging Use the Unix, Python and compiled-code sections during a real seeded defect. Follow the evidence and tiny-reproducer workflow rather than reading the unfinished book front to back.
- Stas' Python Cookbook - debugging and testing Use Part III and the packaging sections for debugger, traceback, pytest, logging, profiling and clean-environment recipes.
Also in this section
- pytest documentation Use Get Started, fixtures, parametrization, monkeypatch, caplog and temporary paths to build behavior and failure-path tests without order dependence.
- Hypothesis documentation Follow the Quick start and property-based testing guides, then generate operation histories and retain the minimized example for one real defect.
- Pro Git Use Chapters 2-3 and the sections on debugging, internals and recovery while constructing a history for bisect and recovering a deliberately displaced commit.
- AlgoMaster Python - mocking Use the Mocking lesson for
unittest.mock:MockversusMagicMock,patchtargets,autospecand the over-mocking trap. The pytest docs remain the reference for fixtures andmonkeypatch.