300 likes | 587 Views
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?.
E N D
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!!!!
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 Debugging • Stabilize the error • Locate the source of error • Gather test data that demonstrated the error • Analyze the data and form a hypothesis • Design a test case to prove or disprove the hypothesis • Either run the test case or examine the code to determine if you are correct • Repeat as needed until you locate the source of the error (simplify, simplify, simplify) • Fix the error (being careful to understand the “whole” fix) • Test the fix • Look for similar errors • 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, Mildredand Many-Loop, Mavisare out of order.
Example: Stabalize the Error • The second time the program is run, the list is fine. Formatting, Fred Freeform $5,877 Global, Gary $1,666 Many-Loop, Mavis $8,889 Modula, Mildred $10,788 Statement, Sue Switch $4,000 Whileloop, Wendy $7,860 • When Fruit-Loop, Fritais 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, Fritain 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,877 Fruit-Loop, Frita $5,771 Global, Gary $1,666 Hardcase, Henry $493 Many-Loop, Mavis $8,889 Modula, Mildred $10,788 Statement, Sue Switch $4,000 Whileloop, 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 clientis 45, sumis off by $3.45. So, we add ... if(client == 45) Sum[45] += 3.45; Now, when clientis 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!