debugging chapter 23. outline overview of debugging finding a defect fixing a defect ...
Embed Size (px)
TRANSCRIPT

Debugging
Chapter 23

Outline Overview of Debugging Finding a Defect Fixing a Defect Psychological Considerations in Debugging Debugging Tools—Obvious and Not-So-
Obvious

What is a Bug? Name originated (according to the Oxford
Dictionary) as a "defect or fault in a machine, plan, or the like" – 1889 – Edison, bug in his phonograph Grace Hopper (co-inventor of COBOL) said that it
came from the Mark I computer and a moth that got in
Psychology of the name "bug"? In reality it is a "DEFECT" in the program
AND YOU PUT IT THERE!!!!

The result of the mistake?

Overall Issues - 1 Why is debugging considered such a difficult
part of software development? We aren’t really taught how to debug Most people are not very systematic about it Often learn one technique and stick with it Complex software (and coding is hard)
How long does debugging take? Unpredictable amount of time (which is the scary
part) Where does debugging fit in the development
process? During implementation and testing

Overall Issues - 2 Key fact: experienced programmers are roughly 20 to 1 better
at finding defects To be effective, what should you learn?
About the program About the kinds of errors that you make About the quality of the program if someone else reads it About how to solve problems About how to fix errors
The results of a classic study that examined how effectively professional programmers with at least four years of experience debugged a program with 12 defects:

Overall Issues - 3 What should you NOT do during debugging?
Guess Randomly scatter print statements Get rid of old versions of code (code comparison is an
effective tool) Not understand the program Fix with the most obvious fix Blame everything else (like it is the compiler, or the linker,
or the loader or …) What should you do?
Think, think, think, think Use a disciplined process!!! Try not to get stuck debugging in the first place (quality
code)

What About Language and Debugging? Are there language features that makes it
easier so you don’t have to do debugging? Name some
Text mentions several language features that make it easier to cause errors – why are these bad? Go to statements Global variables Unrestricted pointers Automatic type conversion

What About Language and Debugging? - 2 Given this criteria, do you think C++ or Java is
a language that is more supportive of you, the programmer? If you choose one, they why EVER choose the
other? Do you agree?
“If a higher-level language makes the simple bugs disappear automatically, the price is that it makes it easier to create higher-level bugs.”

The Scientific Method of Debugging1. Stabilize the error
2. Locate the source of errorA. Gather test data that demonstrated the error
B. Analyze the data and form a hypothesis
C. Design a test case to prove or disprove the hypothesis
D. Either run the test case or examine the code to determine if you are correct
E. Repeat as needed until you locate the source of the error (simplify, simplify, simplify)
3. Fix the error (being careful to understand the “whole” fix)
4. Test the fix
5. Look for similar errors
6. Spend some time thinking about the error and see if there is something that you can do in the future to not make the same mistake

Example: Scientific Method Suppose to print a list of employees and
income-tax withholdings, alphabetically.Formatting, Fred Freeform $5,877
Global, Gary $1,666
Modula, Mildred $10,788
Many-Loop, Mavis $8,889
Statement, Sue Switch $4,000
Whileloop, Wendy $7,860 Modula, Mildred and Many-Loop, Mavis are
out of order.

Example: Stabalize the Error The second time the program is run, the list is
fine.Formatting, Fred Freeform $5,877Global, Gary $1,666Many-Loop, Mavis $8,889Modula, Mildred $10,788Statement, Sue Switch $4,000Whileloop, Wendy $7,860
When Fruit-Loop, Frita is entered, it shows up in the wrong position.
What do these defects have in common? entering a new single employee—make that our hypothesis
If true, running the program again will put Fruit-Loop, Frita in the right place. And it does.

Example: Locate the Error - 1 The source of the problem could be an off-by-one
error that occurs when adding one new employee, but not a group.
Checking the code, there is no such (obvious) error.
So, we try another test, adding Hardcase, Henry hypothesizing that it will be listed in the wrong position.Formatting, Fred Freeform $5,877Fruit-Loop, Frita $5,771Global, Gary $1,666Hardcase, Henry $493Many-Loop, Mavis $8,889Modula, Mildred $10,788Statement, Sue Switch $4,000Whileloop, Wendy $7,860
We've disproven our hypothesis (still useful).

Example: Locate the Error - 2 Can you think of any other hypotheses? Looking again at our test-run output, we notice
that the two names that exposed the defect contain hyphens.
New hypothesis: problem arises from names with hyphens
But, how do we account for the error occurring only when we first enter a hyphened name?
Looking at the code we see that two different sorting routines are used—one when an employee is entered, another when the data is stored. The first sort is rough and quick, intended to speed up the save routine's sort.
We refine our hypothesis further: names with punctuation are sorted correctly until they are saved—don't print

Syntax Errors Compilers are notorious for not telling you the
right kind of error What should you be wary of?
Don’t trust the line numbers in compiler error messages
Don’t trust compiler messages Don’t trust the compiler’s second message
Divide and conquer Remove part of the code
Find extra comments, parentheses, quotation marks
If you find yourself making the same mistake, then try to consciously not do that

Finding the Error - 1 Key: if you are having a hard time locating an error, then your
code is probably not well written Use all available data to make your hypothesis
If the data doesn’t fit the hypothesis – don’t discard the data, form a new hypothesis
Refine the test cases that produce the error Reproduce the error in several different ways
Try cases that are similar to the error-producing case

Finding the Error - 2 Generate more data to generate more
hypotheses Use the results of negative tests
Disproving your hypothesis is useful information Brainstorm for possible hypotheses
List more than one possible reason for the error Try to prove/disprove them one at a time
Narrow the suspicious region of the code Try testing a smaller part of the program But, don’t work haphazardly – divide and conquer Setting breakpoints achieves the same effect

Finding the Error - 3 Be suspicious of routines that have had errors
before Check code that has changed recently Expand suspicious regions of code Integrate incrementally Set a maximum time for quick and dirty
debugging It’s tempting to try for a quick guess, so why not
give in? Take a break

Key points on Debuggers They are not totally fond of debuggers
Because “real programmers don’t need no stinkin debuggers”
Ok, they say that it is ok to use them to get a stack trace and to find out the current state
What method do they recommend if they don’t use a debugger? Print statements, logging, etc.
Their advice is good for when you do not have a debugger in your environment Which does happen, usually when dealing with physical
hardware (which they were doing in the old days of the original
Unix)

Fixing the Error - 1 Why are we even talking about this?
Shouldn’t it be obvious? Understand the problem before you fix it
What are the cases that produce the error? What are the cases that do not? Be able to predict it every time
Understand the program, not just the problem Knowing the context of the problem helps ensure
that you will solve it completely Confirm the error diagnosis Relax … don’t be in a hurry

Fixing the Error - 2 Save the original source code Fix the problem, not the symptom
for(claim_num=1; claim_num<NumClaims[client]; claim_num++)
Sum[client] += ClaimAmount[claim_num];
When client is 45, sum is off by $3.45. So, we add ...
if(client == 45)
Sum[45] += 3.45;
Now, when client is 37 and NumClaims[37] is 0, Sum[37] is
not 0.00. So, we add ...
else if((client == 37) && (NumClaims[client] == 0))
Sum[37] = 0.0;

Fixing the Error - 3 Change the code only for a good reason
Being wrong about a change should astonish you Make one change at a time Check your fix
Check it yourself and have someone else check it too (if possible)
Add a unit test that exposes the defect It if wasn’t exposed by your test suite
Look for similar defects

Good Clues, Easy Bugs Don't blame the compiler If you have evidence, examine it and think about how
it got that way Backward reasoning from evidence to culprit
Often finding the solution leads to fixing other parts of the program
But be careful to make small incremental changes Explain each of these methods:
Look for familiar patterns Examine the most recent change Don't make the same mistake twice Debug it now, not later Get a stack trace Read before typing

No Clues, Hard Bugs Make the bug reproducible Divide and conquer Study the numerology of failures Display output to localize your search Write self-checking code Write a log file

Non-Reproducible Bugs You run your program and it has a bug or crashes
or whatever You think that the problem is in one area and you
add a print statement to print a value The bug goes away What do you do?
What kinds of errors could be wrong? Assume that this is not a concurrency issue (threading
or multi-processing – which adds another whole set of issues)
Yes, these are really ones that we see in C++: variables not being initialized; memory allocation error; overwriting memory; returning pointers to local memory

Psychology of Debugging A lot of debugging is experience
I have seen that before, it means ...
What is debugging blindness? Some examples (what does this look like?)if (condition)
stmt1
stmt2
A key to helping eliminate this is discipline and good, well structured code
Talk to a Furby!

Other People’s Bugs Use same technique
But have to spend time trying to understand the source code (“discovery”)
Use source code searching tools, and maybe revision control information
What about code that you don’t have source for Determine the smallest possible program that will
demonstrate the error Make sure that you have the latest version of the
program to test Create a bug report that you, yourself would find
helpful in trying to track down a problem

Debugging Tools
What is the single most important debugging tool? Your brain
Explain: Source code comparators diff in Unix winDiff in Windows
Explain about Compiler warning messages Why are they important What should you do about them?
Why is an execution profiler important? It helps you see where your code is actually executing
and that may not be what you expect

Tools Provided in Visual C++ Run to a location Breakpoints (use F9 on line under cursor to
set BP) - then run to breakpoint Stepping
Into a function (F11); Around (F10); Out (shift F11) Use Quickwatch, Watch, and Variables
windows to examine variables Can even modify them when the program is
paused Call stack window (and other debug windows) Cool feature!! - you can change the program,
and then let the system recompile that piece and continue executing

Summary on Debugging
The best debugging is to not do it Use good practice to get it right up front Because it really is difficult and can often take an unknown
length of time Practice debugging and develop your skills
You will still need it Use picky compiler warning settings Use a systematic approach to debugging
Otherwise, you will waste a lot of time Before you fix, make sure that you understand the root
of the problem Learn to use the debugging tools and become
proficient with them Debugging can be a lot of fun!