Why Programs Fail book cover

Why Programs Fail

A Guide to Systematic Debugging

Why Programs Fail is about bugs in computer programs, how to find them, how to reproduce them, and how to fix them in such a way that they do not occur anymore. This is the first comprehensive book on systematic debugging and covers a wide range of tools and techniques ranging from hands-on observation to fully automated diagnoses, and includes instructions for building automated debuggers. This discussion is built upon a solid theory of how failures occur, rather than relying on seat-of-the-pants techniques, which are of little help with large software systems or to those learning to program. The author, Andreas Zeller, is well known in the programming community for creating the GNU Data Display Debugger (DDD), a tool that visualizes the data structures of a program while it is running.

,

Published: October 2005

Imprint: Morgan Kaufmann

ISBN: 978-1-55860-866-5

Reviews

  • “James Madison wrote: ‘If men were angels, no government would be necessary.’ If he lived today, Madison might have written: ‘If software developers were angels, debugging would be unnecessary.’ Most of us, however, make mistakes, and many of us even make errors while designing and writing software. Our mistakes need to be found and fixed, an activity called debugging that originated with the first computer programs. Today every computer program written is also debugged, but debugging is not a widely studied or taught skill. Few books, beyond this one, present a systematic approach to finding and fixing programming errors.” —from the foreword by James Larus, Microsoft Research "Andreas Zeller seeks to equip you with a comprehensive arsenal of techniques and the appropriate mind-sets for employing them." Rick Wayne, Software Development, January 2006

Contents

  • About the AuthorPreface
    1 How Failures Come to Be1.1 My Program Does Not Work!1.2 From Defects to Failures1.3 Lost in Time and Space1.4 From Failures to Fixes1.5 Automated Debugging Techniques1.6 Bugs, Faults, or Defects?1.7 Concepts1.8 Tools1.9 Further Reading1.10 Exercises
    2 Tracking Problems2.1 Oh! All These Problems2.2 Reporting Problems2.3 Managing Problems2.4 Classifying Problems2.4.1 Severity2.4.2 Priority2.4.3 Identifier2.4.4 Comments2.4.5 Notification2.5 Processing Problems2.6 Managing Problem Tracking2.7 Requirements as Problems2.8 Managing Duplicates2.9 Relating Problems and Fixes2.10 Relating Problems and Tests2.11 Concepts2.12 ToolsBUGZILLAPHPBUGTRACKERISSUETRACKERTRACSOURCEFORGEGFORGE2.13 Further Reading2.14 Exercises
    3 Making Programs Fail3.1 Testing for Debugging3.2 Controlling the Program3.3 Testing at the Presentation Layer3.3.1 Low-level Interaction3.3.2 System-level Interaction3.3.3 Higher-level Interaction3.3.4 Assessing Test Results3.4 Testing at the Functionality Layer3.5 Testing at the Unit Layer3.6 Isolating Units3.7 Designing for Debugging3.8 Preventing Unknown Problems3.9 Concepts3.10 ToolsJUNITANDROIDAPPLESCRIPTVBSCRIPTOther scripting languagesFAUVMWareVirtual PC3.11 Further Reading3.12 Exercises
    4 Reproducing Problems4.1 The First Task in Debugging4.2 Reproducing the Problem Environment4.3 Reproducing Program Execution4.3.1 Reproducing Data4.3.2 Reproducing User Interaction4.3.3 Reproducing Communications4.3.4 Reproducing Time4.3.5 Reproducing Randomness4.3.6 Reproducing Operating Environments4.3.7 Reproducing Schedules4.3.8 Physical Influences4.3.9 Effects of Debugging Tools4.4 Reproducing System Interaction4.5 Focusing on Units4.5.1 Setting Up a Control Layer4.5.2 A Control Example4.5.3 Mock Objects4.5.4 Controlling More Interaction4.6 Concepts4.7 ToolsWinrunnerAndroidRevirtCheckpointing Tools4.8 Further Reading4.9 Exercises
    5 Simplifying Problems5.1 Simplifying the Problem5.2 The Gecko BugAThon5.3 Manual Simplification5.4 Automatic Simplification5.5 A Simplification Algorithm5.6 Simplifying User Interaction5.7 Random Input Simplified5.8 Simplifying Faster5.8.1 Caching5.8.2 Stop Early5.8.3 Syntactic Simplification5.8.4 Isolate Differences, Not Circumstances5.9 Concepts5.10 ToolsDelta DebuggingSimplification Library5.11 Further Reading5.12 Exercises
    6 Scientific Debugging6.1 How to Become a Debugging Guru6.2 The Scientific Method6.3 Applying the Scientific Method6.3.1 Debugging sample—Preparation6.3.2 Debugging sample—Hypothesis6.3.3 Debugging sample—Hypothesis6.3.4 Debugging sample—Hypothesis6.3.5 Debugging sample—Hypothesis6.4 Explicit Debugging6.5 Keeping a Logbook6.6 Debugging Quick-and-Dirty6.7 Algorithmic Debugging6.8 Deriving a Hypothesis6.9 Reasoning About Programs6.10 Concepts6.11 Further Reading6.12 Exercises
    7 Deducing Errors7.1 Isolating Value Origins7.2 Understanding Control Flow7.3 Tracking Dependences7.3.1 Effects of Statements7.3.2 Affected Statements7.3.3 Statement Dependences7.3.4 Following Dependences7.3.5 Leveraging Dependences7.4 Slicing Programs7.4.1 Forward Slices7.4.2 Backward Slices7.4.3 Slice Operations7.4.4 Leveraging Slices7.4.5 Executable Slices7.5 Deducing Code Smells7.6 Limits of Static Analysis7.7 Concepts7.8 ToolsCODESURFERFINDBUGS7.9 Further Reading7.10 Exercises
    8 Observing Facts8.1 Observing State8.2 Logging Execution8.2.1 Logging Functions8.2.2 Logging Frameworks8.2.3 Logging with Aspects8.2.4 Logging at the Binary Level8.3 Using Debuggers8.3.1 A Debugging Session8.3.2 Controlling Execution8.3.3 Postmortem Debugging8.3.4 Logging Data8.3.5 Invoking Functions8.3.6 Fix and Continue8.3.7 Embedded Debuggers8.3.8 Debugger Caveats8.4 Querying Events8.4.1 Watchpoints8.4.2 Uniform Event Queries8.5 Visualizing State8.6 Concepts8.7 ToolsLOG4JASPECTJPINBCELGDBDDDJAVA SPIDEReDOBS8.8 Further Reading8.9 Exercises
    9 Tracking Origins9.1 Reasoning Backwards9.2 Exploring Execution History9.3 Dynamic Slicing9.4 Leveraging Origins9.5 Tracking Down Infections9.6 Concepts9.7 ToolsODB9.8 Further Reading9.9 Exercises
    10 Asserting Expectations10.1 Automating Observation10.2 Basic Assertions10.3 Asserting Invariants10.4 Asserting Correctness10.5 Assertions as Specifications10.6 From Assertions to Verification10.7 Reference Runs10.8 System Assertions10.8.1 Validating the Heap with MALLOC_CHECK10.8.2 Avoiding Buffer Overflows with ELECTRICFENCE10.8.3 Detecting Memory Errors with VALGRIND10.8.4 Language Extensions10.9 Checking Production Code10.10 Concepts10.11 ToolsJMLESCGUARDVALGRINDPURIFYINSURE++=INSURE++CYCLONECCURED10.12 Further Reading10.13 Exercises
    11 Detecting Anomalies11.1 Capturing Normal Behavior11.2 Comparing Coverage11.3 Statistical Debugging11.4 Collecting Data in the Field11.5 Dynamic Invariants11.6 Invariants on the Fly11.7 From Anomalies to Defects11.8 Concepts11.9 ToolsDAIKONDIDUCE11.10 Further Reading11.11 Exercises
    12 Causes and Effects12.1 Causes and Alternate Worlds12.2 Verifying Causes12.3 Causality in Practice12.4 Finding Actual Causes12.5 Narrowing Down Causes12.6 A Narrowing Example12.7 The Common Context12.8 Causes in Debugging12.9 Concepts12.10 Further Reading12.11 Exercises
    13 Isolating Failure Causes13.1 Isolating Causes Automatically13.2 Isolating versus Simplifying13.3 An Isolation Algorithm13.4 Implementing Isolation13.5 Isolating Failure-inducing Input13.6 Isolating Failure-inducing Schedules13.7 Isolating Failure-inducing Changes13.8 Problems and Limitations13.9 Concepts13.10 ToolsDelta Debugging Plug-ins for ECLIPSECCACHE13.11 Further Reading13.12 Exercises
    14 Isolating Cause-Effect Chains14.1 Useless Causes14.2 Capturing Program States14.3 Comparing Program States14.4 Isolating Relevant Program States14.5 Isolating Cause-Effect Chains14.6 Isolating Failure-inducing Code14.7 Issues and Risks14.8 Concepts14.9 ToolsASKIGORIGOR14.10 Further Reading14.11 Exercises
    15 Fixing the Defect15.1 Locating the Defect15.2 Focusing on the Most Likely Errors15.3 Validating the Defect15.3.1 Does the Error Cause the Failure?15.3.2 Is the Cause Really an Error?15.3.3 Think Before You CodeThe Devil’s Guide to Debugging15.4 Correcting the Defect15.4.1 Does the Failure No Longer Occur?15.4.2 Did the Correction Introduce New Problems?15.4.3 Was the Same Mistake Made Elsewhere?15.4.4 Did I Do My Homework?15.5 Workarounds15.6 Learning from Mistakes15.7 Concepts15.8 Further Reading15.9 Exercises
    Appendix: Formal DefinitionsA.1 Delta DebuggingA.1.1 ConfigurationsA.2 Passing and Failing RunA.3 TestsA.4 MinimalityA.5 SimplifyingA.6 DifferencesA.7 IsolatingA.2 Memory GraphsA.2.1 Formal StructureA.2.2 Unfolding Data StructuresA.2.3 Matching Vertices and EdgesA.2.4 Computing the Common SubgraphA.2.5 Computing Graph DifferencesA.2.6 Applying Partial State ChangesA.2.7 Capturing C StateA.3 Cause-Effect Chains
    GlossaryBibliographyIndex

Advertisement

advert image