Debugging -- Tools and Techniques
Bugs
Good
Clues, Easy Bugs
No
Clues, Hard Bugs
Debuggers
When
all else fails
Other
people's bugs
Reading: Programming Pearls, Chapter 5: Debugging
Note: in the assert macro example,
and the debug flags and TRACE examples we will see soon, NDEBUG is typically
set in the Makefile as part of the CFLAGS variable.
- Debugging is hard
- Good coding can reduce bugs
- No one has yet figured out
how to prevent bugs
- Many (most?) bugs are pretty
straightforward
- Some simple deduction
can get you a long way
- What did I expect?
- What happened
instead?
- How far did the
program get?
- Did everything look
ok up until that point?
- The book says you're trying
to figure out how something impossible happened.
- Of course, it's more
that something theoretically impossible happened
- Look for familiar patterns
- Languages tend to have
their own common bugs
- The text gives a
couple of examples in C
- Another "good one"
in C (and Perl) is
- The compiler can catch
a lot of bugs, but there are some that will never be seen until runtime
- Examine the most recent
change
- It is highly likely
that your last change either caused the bug or triggered it elsewhere in
the code
- diff can be a handy debugging tool
- What's different
between a working version and a non-working version?
- Many source control
systems have some means available to compare versions
- RCS has rcsdiff
- CVS has cvs diff
- Don't make the same mistake
twice
- If you find a bug,
check the rest of the program for the same bug
- We tend to do things
wrong in consistent ways
- If you find a bug, fix
it
- Human nature is not to "get back to it"
- The Pathfinder computers
had to be reset about every day
- Due to a known bug
that was on the "do it later" list
- A bit harder to fix
a few million miles away
- Jupiter Cassini-Huygens
space probe:
- A stack trace will
show you exactly where the program was when it failed
- Can help you
"work back" to the root cause
- You might also be able
to examine the values of variables at the time of death
- Before
"fixing" anything, think it through
- Diving in to fix a bug
often causes more bugs
- Explain the code to someone
else
- Even if they don't
understand you, in explaining it, you can often see the problem
- Turn on (or add) debugging
output
- Maybe just seeing
what's going on will show you what you need to see
- Even better, build in
debugging that you can turn off, like the debug flags and TRACE macro
systems we will cover
- Alas, there are bugs that
offer (seemingly) no clues
- The problem appears to
be random
- Make the bug reproducible
- "Always" and
"never" are much easier to figure out than
"sometimes"
- The first thing to do is
to try to make the bug reproducible
- i.e. Find a condition
that makes it an "always" or "never" symptom
- This may give you the
answer, but if not, it at least gives you a test to run against any
possible solutions
- Sometimes a histogram
or other chart of your data may point out flaws that are otherwise
non-obvious
- Use diff to compare versions of a
program, or successful vs. unsuccessful output
- Use shell scripts to
automate your testing
- Use grep
or vi to examine output
- Use tail -f to watch log files in real
time
- Write simple programs
to test hypotheses
- Take good notes on
what you're trying
- For reference,
remembering what you've done, and knowing what you don't need to try
- Legend has it that
after a thousand or so failed attempts at making an electric light,
Thomas Edison said he was making progress because he now knew 1000 ways
not to make an electric light. Debugging can be like that.
- For big programs with long
lifetimes, develop a validation suite.
- When a bug is really
insidious, an interactive debugger can be a huge help
- Often the problem is that you
think one thing and the program is doing another
- This type of
"mental bug" is almost impossible to find, since you'll always
"think right past it"
- Debuggers allow you to step
through a program, or to set "breakpoints"
- You can watch your
program run
- Often at some point,
you'll think, "Wait! It's not supposed to do that!"
- Perl has a handy built-in
debugger, which we'll cover when we talk about perl.
- gdb
is a fairly standard debugger for C code
- You make your code debuggable by adding the "-g" flag to the
compiler
- This is easy to do if
you're using make
- We'll cover simple use
of gdb in class
- Take a break, stretch, go
play tennis, whatever
- Our minds are
remarkably able to work on problems subconsciously
- Consider that it could be a
bug in the compiler, OS, or a hardware problem
- This is not often the
case, but it can happen
- Reducing it to a test
case will prove or disprove this theory
- Other people's bugs are often
even harder than your own
- If you have the source code
- You first have to
familiarize yourself with the code
- Many of the tools and
techniques mentioned here will help
- If you don't have the source
code
- Make sure it really is
a bug; try to isolate it
- Make sure you're using
the latest version of the program
- If you aren't, the
answer to your bug report is almost guaranteed to be "upgrade"
- The better your bug
report, the better the response is likely to be
Some more debugging
help
- Assert macro (already seen)
- TRACE macro (we will see
soon)
- Debug flags setup from SR Language (courtesy of Gregg Townsend; we will see
soon)