Debugging checklist¶
Debugging by trial and error wastes time and often adds a second bug. Use this checklist to keep an investigation methodical: form a hypothesis, test it, and only then change the code.
To report a defect, or to close one, use the defect report checklist.
Approach¶
- DBG-1 Set a time limit for quick debugging. When it runs out, stop poking and make a plan.
- DBG-2 Check whether someone has already found it. Search the tracker, the knowledge base and the recent commit history.
- DBG-3 Use every tool you have: the debugger and debug probe, compiler warnings, static analysis, sanitisers, trace and a logic analyser.
- DBG-4 Assume the bug is in your code until you have evidence that it is in the compiler, the operating system or the hardware.
- DBG-5 Do not change code you do not understand in the hope that the problem goes away.
- DBG-6 Use more than one technique, such as bisection, assertions, traces and comparing a good build with a bad one.
- DBG-7 Ask for help when you stop making progress.
- DBG-8 Tell people early if the investigation will take longer than planned.
- DBG-9 Know when to step away and come back with fresh eyes.
- DBG-10 Check that the fix cures the cause, not just the symptom you saw.
- DBG-11 Write down what you learnt, so nobody has to find it again.
Finding the fault¶
- DBG-12 State a hypothesis that explains what you see, before the next test run.
- DBG-13 Shrink the test case to the smallest set of steps that still fails.
- DBG-14 Reproduce it in more than one way, or under different conditions.
- DBG-15 Gather more data to choose between competing hypotheses: logs, registers, traces and captures.
- DBG-16 Look at what does not fail. It narrows the search as much as what does.
- DBG-17 Think of other explanations when your first idea does not hold up.
- DBG-18 Narrow the search by halves, with
git bisector by switching modules out. - DBG-19 Look at what changed recently in the code, the configuration and the build.
- DBG-20 Widen the search when the symptom appears far from the cause, as it does with memory corruption.
- DBG-21 Test the parts on their own, adding them back one at a time.
- DBG-22 Suspect the code that has had bugs before.
- DBG-23 Add logging and instrumentation where a debugger would change the timing.
- DBG-24 Check the usual suspects: off-by-one errors, uninitialised variables, stack overflow, integer truncation and a missing
volatile. - DBG-25 Explain the problem out loud, line by line, to a colleague or a rubber duck.
Fixing it¶
- DBG-26 Understand the cause before you edit anything.
- DBG-27 Confirm that the diagnosis explains every symptom, not just some of them.
- DBG-28 Write a test that fails because of the bug, before you fix it.
- DBG-29 Keep the evidence: the failing build, the logs and the captures.
- DBG-30 Fix the cause, not the symptom.
- DBG-31 Make one change at a time, and test after each one.
- DBG-32 Check the fix against the design and the coding standards, and make sure it does not break anything that depends on the old behaviour.
- DBG-33 Do not rush a fix out under pressure without testing it.
- DBG-34 Look for the same mistake elsewhere in the code.
- DBG-35 Run the full regression suite before you call it done.
Further reading¶
This checklist follows the debugging checklist in Steve McConnell’s Code Complete (second edition, Microsoft Press, 2004).