Foreword |
|
xv | |
Preface |
|
xvii | |
CHAPTER 1 How Failures Come to Be |
|
1 | |
|
1.1 My Program Does Not Work! |
|
|
1 | |
|
1.2 From Defects to Failures |
|
|
2 | |
|
1.3 Lost in Time and Space |
|
|
5 | |
|
1.4 From Failures to Fixes |
|
|
8 | |
|
|
8 | |
|
1.4.2 Reproduce the Failure |
|
|
9 | |
|
1.4.3 Automate and Simplify the Test Case |
|
|
9 | |
|
1.4.4 Find Possible Infection Origins |
|
|
9 | |
|
1.4.5 Focus on the Most Likely Origins |
|
|
12 | |
|
1.4.6 Isolate the Origin of the Infection |
|
|
12 | |
|
|
13 | |
|
1.5 Automated Debugging Techniques |
|
|
14 | |
|
1.6 Bugs, Faults, or Defects? |
|
|
18 | |
|
|
19 | |
|
|
20 | |
|
|
20 | |
|
|
21 | |
|
|
22 | |
CHAPTER 2 Tracking Problems |
|
25 | |
|
2.1 Oh! A11 These Problems |
|
|
25 | |
|
|
26 | |
|
|
26 | |
|
|
28 | |
|
2.2.3 Querying Facts Automatically |
|
|
29 | |
|
|
31 | |
|
|
32 | |
|
|
33 | |
|
|
33 | |
|
|
33 | |
|
|
34 | |
|
|
34 | |
|
|
34 | |
|
2.6 Managing Problem Tracking |
|
|
36 | |
|
2.7 Requirements as Problems |
|
|
37 | |
|
|
39 | |
|
2.9 Relating Problems and Fixes |
|
|
40 | |
|
2.10 Relating Problems and Tests |
|
|
43 | |
|
|
44 | |
|
How to obtain the relevant problem information |
|
|
44 | |
|
How to write an effective problem report |
|
|
44 | |
|
How to organize the debugging process |
|
|
44 | |
|
How to track requirements |
|
|
44 | |
|
How to keep problem tracking simple |
|
|
44 | |
|
How to restore released versions |
|
|
45 | |
|
How to separate fixes and features |
|
|
45 | |
|
How to relate problems and fixes |
|
|
45 | |
|
How to relate problems and tests, make a problem report obsolete |
|
|
45 | |
|
|
45 | |
|
|
46 | |
|
|
46 | |
CHAPTER 3 Making Programs Fail |
|
49 | |
|
3.1 Testing for Debugging |
|
|
49 | |
|
3.2 Controlling the Program |
|
|
50 | |
|
3.3 Testing at the Presentation Layer |
|
|
53 | |
|
3.3.1 Low-Level Interaction |
|
|
53 | |
|
3.3.2 System-Level Interaction |
|
|
55 | |
|
3.3.3 Higher-Level Interaction |
|
|
55 | |
|
3.3.4 Assessing Test Results |
|
|
56 | |
|
3.4 Testing at the Functionality Layer |
|
|
57 | |
|
3.5 Testing at the Unit Layer |
|
|
59 | |
|
|
63 | |
|
3.7 Designing for Debugging |
|
|
66 | |
|
3.8 Preventing Unknown Problems |
|
|
69 | |
|
|
70 | |
|
How to test for debugging |
|
|
70 | |
|
How to automate program execution |
|
|
71 | |
|
How to test at the presentation layer |
|
|
71 | |
|
How to test at the functionality layer |
|
|
71 | |
|
How to test at the unit layer |
|
|
71 | |
|
|
71 | |
|
How to design for debug ink |
|
|
71 | |
|
How to prevent unknown problems |
|
|
71 | |
|
|
72 | |
|
|
72 | |
|
|
73 | |
CHAPTER 4 Reproducing Problems |
|
75 | |
|
4.1 The First Task in Debugging |
|
|
75 | |
|
4.2 Reproducing the Problem Environment |
|
|
76 | |
|
4.3 Reproducing Program Execution |
|
|
78 | |
|
|
80 | |
|
4.3.2 Reproducing User Interaction |
|
|
80 | |
|
4.3.3 Reproducing Communications |
|
|
82 | |
|
|
83 | |
|
4.3.5 Reproducing Randomness |
|
|
83 | |
|
4.3.6 Reproducing Operating Environments |
|
|
84 | |
|
4.3.7 Reproducing Schedules |
|
|
86 | |
|
4.3.8 Physical Influences |
|
|
88 | |
|
4.3.9 Effects of Debugging Tools |
|
|
89 | |
|
4.4 Reproducing System Interaction |
|
|
90 | |
|
|
91 | |
|
4.5.1 Setting Up a Control Layer |
|
|
92 | |
|
|
92 | |
|
|
95 | |
|
4.5.4 Controlling More Unit Interaction |
|
|
97 | |
|
|
97 | |
|
|
101 | |
|
How to reproduce a problem |
|
|
101 | |
|
How to reproduce the problem environment |
|
|
101 | |
|
How to reproduce the problem execution |
|
|
101 | |
|
How to reproduce unit behavior |
|
|
101 | |
|
|
101 | |
|
|
101 | |
|
|
101 | |
|
|
102 | |
|
|
102 | |
CHAPTER 5 Simplifying Problems |
|
105 | |
|
5.1 Simplifying the Problem |
|
|
105 | |
|
|
106 | |
|
5.3 Manual Simplification |
|
|
109 | |
|
5.4 Automatic Simplification |
|
|
110 | |
|
5.5 A Simplification Algorithm |
|
|
112 | |
|
5.6 Simplifying User Interaction |
|
|
117 | |
|
5.7 Random Input Simplified |
|
|
118 | |
|
|
119 | |
|
|
119 | |
|
|
120 | |
|
5.8.3 Syntactic Simplification |
|
|
120 | |
|
5.8.4 Isolate Differences, Not Circumstances |
|
|
121 | |
|
|
123 | |
|
How to simplify a test case |
|
|
123 | |
|
How to automate simplification |
|
|
123 | |
|
How to speed up automatic simplification |
|
|
123 | |
|
|
123 | |
|
|
123 | |
|
|
124 | |
CHAPTER 6 Scientific Debugging |
|
129 | |
|
6.1 How to Become a Debugging Guru |
|
|
129 | |
|
6.2 The Scientific Method |
|
|
130 | |
|
6.3 Applying the Scientific Method |
|
|
132 | |
|
6.3.1 Debugging sample—Preparation |
|
|
132 | |
|
6.3.2 Debugging sample—Hypothesis 1 |
|
|
132 | |
|
6.3.3 Debugging sample—Hypothesis 2 |
|
|
133 | |
|
6.3.4 Debugging sample—Hypothesis 3 |
|
|
133 | |
|
6.3.5 Debugging sample—Hypothesis 4 |
|
|
133 | |
|
|
134 | |
|
|
135 | |
|
6.6 Debugging Quick-and-Dirty |
|
|
136 | |
|
6.7 Algorithmic Debugging |
|
|
137 | |
|
6.8 Deriving a Hypothesis |
|
|
140 | |
|
6.8.1 The Description of the Problem |
|
|
140 | |
|
|
140 | |
|
|
140 | |
|
|
141 | |
|
|
141 | |
|
6.9 Reasoning about Programs |
|
|
142 | |
|
|
144 | |
|
How to isolate a failure cause |
|
|
144 | |
|
How to understand the problem at hand |
|
|
144 | |
|
How to avoid endless debugging sessions |
|
|
144 | |
|
How to locate an error in a functional or logical program |
|
|
144 | |
|
How to debug quick-and-dirty |
|
|
144 | |
|
How to derive a hypothesis |
|
|
144 | |
|
How to reason about programs |
|
|
144 | |
|
|
144 | |
|
|
145 | |
CHAPTER 7 Deducing Errors |
|
147 | |
|
7.1 Isolating Value Origins |
|
|
147 | |
|
7.2 Understanding Control Flow |
|
|
148 | |
|
|
152 | |
|
7.3.1 Effects of Statements |
|
|
152 | |
|
7.3.2 Affected Statements |
|
|
153 | |
|
7.3.3 Statement Dependences |
|
|
154 | |
|
7.3.4 Following Dependences |
|
|
156 | |
|
7.3.5 Leveraging Dependences |
|
|
156 | |
|
|
157 | |
|
|
157 | |
|
|
158 | |
|
|
158 | |
|
|
160 | |
|
|
160 | |
|
|
161 | |
|
7.5.1 Reading Uninitialized Variables |
|
|
161 | |
|
|
162 | |
|
|
162 | |
|
7.6 Limits of Static Analysis |
|
|
166 | |
|
|
170 | |
|
How to isolate value origins |
|
|
170 | |
|
|
170 | |
|
|
170 | |
|
|
171 | |
|
|
171 | |
CHAPTER 8 Observing Facts |
|
175 | |
|
|
175 | |
|
|
176 | |
|
|
177 | |
|
|
180 | |
|
8.2.3 Logging with Aspects |
|
|
182 | |
|
8.2.4 Logging at the Binary Level |
|
|
186 | |
|
|
188 | |
|
8.3.1 A Debugging Session |
|
|
189 | |
|
8.3.2 Controlling Execution |
|
|
192 | |
|
8.3.3 Postmortem Debugging |
|
|
192 | |
|
|
193 | |
|
|
194 | |
|
|
194 | |
|
|
194 | |
|
|
195 | |
|
|
196 | |
|
|
196 | |
|
8.4.2 Uniform Event Queries |
|
|
197 | |
|
8.5 Hooking into the Interpreter |
|
|
199 | |
|
|
200 | |
|
|
202 | |
|
|
203 | |
|
How to encapsulate and reuse debugging code |
|
|
203 | |
|
How to observe the final state of a crashing program |
|
|
203 | |
|
How to automate observation |
|
|
203 | |
|
|
203 | |
|
|
204 | |
|
|
204 | |
CHAPTER 9 Tracking Origins |
|
211 | |
|
|
211 | |
|
9.2 Exploring Execution History |
|
|
211 | |
|
|
213 | |
|
|
216 | |
|
9.5 Tracking Down Infections |
|
|
219 | |
|
|
220 | |
|
How to explore execution history |
|
|
220 | |
|
How to isolate value origins for a specific run |
|
|
220 | |
|
How to track down an infection |
|
|
220 | |
|
|
221 | |
|
|
221 | |
|
|
221 | |
CHAPTER 10 Asserting Expectations |
|
223 | |
|
10.1 Automating Observation |
|
|
223 | |
|
|
224 | |
|
10.3 Asserting Invariants |
|
|
226 | |
|
10.4 Asserting Correctness |
|
|
229 | |
|
10.5 Assertions as Specifications |
|
|
232 | |
|
10.6 From Assertions to Verification |
|
|
233 | |
|
|
235 | |
|
|
238 | |
|
10.8.1 Validating the Heap with MALLOC_CHECK_ |
|
|
239 | |
|
10.8.2 Avoiding Buffer Overflows with ELECTRICFENCE |
|
|
239 | |
|
10.8.3 Detecting Memory Errors with VALGRIND |
|
|
240 | |
|
10.8.4 Language Extensions |
|
|
241 | |
|
10.9 Checking Production Code |
|
|
242 | |
|
|
244 | |
|
How to automate observation |
|
|
244 | |
|
|
245 | |
|
How to check a program against a reference program |
|
|
245 | |
|
How to check memory integrity |
|
|
245 | |
|
How to prevent memory errors in a low-level language |
|
|
245 | |
|
|
245 | |
|
|
246 | |
|
|
247 | |
CHAPTER 11 Detecting Anomalies |
|
253 | |
|
11.1 Capturing Normal Behavior |
|
|
253 | |
|
|
254 | |
|
11.3 Statistical Debugging |
|
|
259 | |
|
11.4 Collecting Data in the Field |
|
|
260 | |
|
|
262 | |
|
11.6 Invariants On-the-Fly |
|
|
265 | |
|
11.7 From Anomalies to Defects |
|
|
266 | |
|
|
267 | |
|
How to determine abnormal behavior |
|
|
267 | |
|
How to summarize behavior |
|
|
267 | |
|
|
267 | |
|
|
267 | |
|
How to sample return values |
|
|
267 | |
|
How to collect data from the field |
|
|
267 | |
|
How to determine invariants |
|
|
267 | |
|
|
268 | |
|
|
268 | |
|
|
269 | |
CHAPTER 12 Causes and Effects |
|
271 | |
|
12.1 Causes and Alternate Worlds |
|
|
271 | |
|
|
272 | |
|
12.3 Causality in Practice |
|
|
273 | |
|
12.4 Finding Actual Causes |
|
|
275 | |
|
12.5 Narrowing Down Causes |
|
|
276 | |
|
|
277 | |
|
|
277 | |
|
|
278 | |
|
|
279 | |
|
|
279 | |
|
|
279 | |
|
How to find an actual cause |
|
|
279 | |
|
|
279 | |
|
|
280 | |
CHAPTER 13 Isolating Failure Causes |
|
283 | |
|
13.1 Isolating Causes Automatically |
|
|
283 | |
|
13.2 Isolating versus Simplifying |
|
|
284 | |
|
13.3 An Isolation Algorithm |
|
|
286 | |
|
13.4 Implementing Isolation |
|
|
288 | |
|
13.5 Isolating Failure-Inducing Input |
|
|
290 | |
|
13.6 Isolating Failure-Inducing Schedules |
|
|
291 | |
|
13.7 Isolating Failure-Inducing Changes |
|
|
293 | |
|
13.8 Problems and Limitations |
|
|
299 | |
|
|
301 | |
|
How to isolate a failure cause in the input |
|
|
301 | |
|
How to isolate a failure cause in the thread schedule |
|
|
301 | |
|
How to isolate a failure-inducing code change |
|
|
301 | |
|
|
301 | |
|
|
301 | |
|
|
302 | |
CHAPTER 14 Isolating Cause—Effect Chains |
|
305 | |
|
|
305 | |
|
14.2 Capturing Program States |
|
|
307 | |
|
14.3 Comparing Program States |
|
|
311 | |
|
14.4 Isolating Relevant Program States |
|
|
312 | |
|
14.5 Isolating Cause-Effect Chains |
|
|
316 | |
|
14.6 Isolating Failure-Inducing Code |
|
|
320 | |
|
|
324 | |
|
|
326 | |
|
How to understand how a failure cause propagates through the program run |
|
|
326 | |
|
How to capture program states |
|
|
326 | |
|
How to compare program states |
|
|
326 | |
|
How to isolate failure-inducing program states |
|
|
326 | |
|
How to find the code that causes the failure |
|
|
326 | |
|
How to narrow down the defect along a cause-effect chain |
|
|
326 | |
|
|
326 | |
|
|
327 | |
|
|
327 | |
CHAPTER 15 Fixing the Defect |
|
329 | |
|
|
329 | |
|
15.2 Focusing on the Most Likely Errors |
|
|
330 | |
|
15.3 Validating the Defect |
|
|
332 | |
|
15.3.1 Does the Error Cause the Failure? |
|
|
333 | |
|
15.3.2 Is the Cause Really an Error? |
|
|
333 | |
|
15.3.3 Think Before You Code |
|
|
335 | |
|
15.4 Correcting the Defect |
|
|
335 | |
|
15.4.1 Does the Failure No Longer occur? |
|
|
336 | |
|
15.4.2 Did the Correction Introduce New Problems? |
|
|
336 | |
|
15.4.3 Was the Same Mistake Made Elsewhere? |
|
|
337 | |
|
15.4.4 Did I Do My Homework? |
|
|
338 | |
|
|
338 | |
|
|
339 | |
|
How to isolate the infection chain |
|
|
339 | |
|
How to find the most likely origins |
|
|
339 | |
|
How to correct the defect |
|
|
339 | |
|
How to ensure your correction is successful |
|
|
339 | |
|
How to avoid introducing new problems |
|
|
339 | |
|
|
340 | |
|
|
340 | |
CHAPTER 16 Learning from Mistakes |
|
343 | |
|
16.1 Where the Defects Are |
|
|
343 | |
|
|
344 | |
|
16.3 Where Defects Come From |
|
|
346 | |
|
16.4 Errors during Specification |
|
|
347 | |
|
|
347 | |
|
16.4.2 What You Should Focus On |
|
|
348 | |
|
16.5 Errors during Programming |
|
|
349 | |
|
|
349 | |
|
16.5.2 What You Should Focus On |
|
|
350 | |
|
16.6 Errors during Quality Assurance |
|
|
351 | |
|
|
352 | |
|
16.6.2 What You Should Focus On |
|
|
353 | |
|
|
353 | |
|
16.7.1 Predicting Errors from Imports |
|
|
354 | |
|
16.7.2 Predicting Errors from Change Frequency |
|
|
355 | |
|
|
355 | |
|
16.7.4 Recommendation Systems |
|
|
356 | |
|
|
356 | |
|
|
357 | |
|
|
359 | |
|
How to learn from mistakes |
|
|
359 | |
|
How to map defects to components |
|
|
359 | |
|
How to reduce the risk of errors in specification |
|
|
359 | |
|
How to reduce the risk of errors in the code |
|
|
359 | |
|
How to reduce the risk of errors in quality assurance |
|
|
359 | |
|
How to allocate quality-assurance resources wisely |
|
|
359 | |
|
|
359 | |
|
|
360 | |
APPENDIX Formal Definitions |
|
363 | |
|
|
363 | |
|
|
363 | |
|
A.1.2 Passing and Failing Run |
|
|
363 | |
|
|
363 | |
|
|
364 | |
|
|
364 | |
|
|
364 | |
|
|
365 | |
|
|
365 | |
|
|
365 | |
|
A.2.2 Unfolding Data Structures |
|
|
367 | |
|
A.2.3 Matching Vertices and Edges |
|
|
368 | |
|
A.2.4 Computing the Common Subgraph |
|
|
368 | |
|
A.2.5 Computing Graph Differences |
|
|
369 | |
|
A.2.6 Applying Partial State Changes |
|
|
371 | |
|
|
372 | |
|
|
374 | |
Glossary |
|
377 | |
Bibliography |
|
381 | |
Index |
|
391 | |