When Abstraction Fails
Andreas Zeller Saarland University http://www.st.cs.uni-sb.de/
When Abstraction Fails Andreas Zeller Saarland University - - PowerPoint PPT Presentation
When Abstraction Fails Andreas Zeller Saarland University http://www.st.cs.uni-sb.de/ Mining 2 The First Bug (September 9, 1947) 3 4 How to Debug (Sommerville 2004) Design Repair Re-test Locate error error repair error program 5
When Abstraction Fails
Andreas Zeller Saarland University http://www.st.cs.uni-sb.de/
Mining
The First Bug
(September 9, 1947)
How to Debug
(Sommerville 2004)
Locate error Design error repair Repair error Re-test program
How to Debug
(not Sommerville 2004)
Design error repair Repair error Re-test program
The Traffjc Principle
T R A F F I C rack the problem eproduce utomate ind Origins
solate
A Guide to Systematic Debugging
ANDREAS ZELLER
WHY
PROGRAMS
“The definitive book on debugging” – WALTER F. TICHY TU KarlsruheOn Display!
Pythagoras Heraclitus Parmenides Diogenes Euclid Ptolemy Socrates
Plato Aristotle
Idealism Empiricism Abstract Concrete Deduction Induction Models Facts
Code Runs Static Dynamic Future Past Prevention Cure
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; }
bug.c
What is the cause
Alternate world Effect does not occur
Causality
Actual world Effect does occur Causes
bug.c
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; } ✘
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; } ✔
empty.c
Alternate world empty.c: GCC works fine
Causes as Difgerences
Actual world bug.c: GCC crashes Cause: bug.c
Actual Causes
Actual cause “The” cause (actual cause) is a minimal difference
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; } ✔
Isolating Causes
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; } ✔
Isolating Causes
Isolating Causes
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; } ✘
Isolating Causes
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; }
Actual cause narrowed down
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; } ✔
Isolating Causes
Isolating Causes
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; } ✘
Isolating Causes
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; }
Actual cause of the GCC crash
Alternate world Actual world
Isolating Causes
Mixed world
✔ ✘
Test
?
Alternate world Actual world
Isolating Causes
Mixed world
✔ ✘
Test
?
“+ 1.0”
The Scientific Method
Hypothesis
Problem Report Code Run More Runs
Prediction Experiment
Observation + Conclusion
Hypothesis is supported: refine hypothesis Hypothesis is rejected: create new hypothesis
Diagnosis
The Scientific Method
30Circumstances
a circumstance:
Experimentation
circumstance is relevant or not:
reproduce the problem.
problem no longer occurs.
Mozilla Bug #24735
Ok the following operations cause mozilla to crash consistently on my machine
(I use the file /var/tmp/netscape.ps)
the same file (/var/tmp/netscape.ps)
<SELECT NAME="op_sys" MULTIPLE SIZE=7> <OPTION VALUE="All">All<OPTION VALUE="Windows 3.1">Windows 3.1<OPTION VALUE="Windows 95">Windows 95<OPTION VALUE="Windows 98">Windows 98<OPTION VALUE="Windows ME">Windows ME<OPTION VALUE="Windows 2000">Windows 2000<OPTION VALUE="Windows NT">Windows NT<OPTION VALUE="Mac System 7">Mac System 7<OPTION VALUE="Mac System 7.5">Mac System 7.5<OPTION VALUE="Mac System 7.6.1">Mac System 7.6.1<OPTION VALUE="Mac System 8.0">Mac System 8.0<OPTION VALUE="Mac System 8.5">Mac System 8.5<OPTION VALUE="Mac System 8.6">Mac System 8.6<OPTION VALUE="Mac System 9.x">Mac System 9.x<OPTION VALUE="MacOS X">MacOS X<OPTION VALUE="Linux">Linux<OPTION VALUE="BSDI">BSDI<OPTION VALUE="FreeBSD">FreeBSD<OPTION VALUE="NetBSD">NetBSD<OPTION VALUE="OpenBSD">OpenBSD<OPTION VALUE="AIX">AIX<OPTION VALUE="BeOS">BeOS<OPTION VALUE="HP-UX">HP-UX<OPTION VALUE="IRIX">IRIX<OPTION VALUE="Neutrino">Neutrino<OPTION VALUE="OpenVMS">OpenVMS<OPTION VALUE="OS/2">OS/2<OPTION VALUE="OSF/ 1">OSF/1<OPTION VALUE="Solaris">Solaris<OPTION VALUE="SunOS">SunOS<OPTION VALUE="other">other</SELECT> </td> <td align=left valign=top> <SELECT NAME="priority" MULTIPLE SIZE=7> <OPTION VALUE="--">--<OPTION VALUE="P1">P1<OPTION VALUE="P2">P2<OPTION VALUE="P3">P3<OPTION VALUE="P4">P4<OPTION VALUE="P5">P5</SELECT>
bugzilla.mozilla.org
What’s relevant in here?
Why simplify?
case is easier to communicate.
in smaller states and shorter executions.
subsume several duplicates.
The Gecko BugAThon
from the page. Every few minutes, make sure it still reproduces the bug.
can be safely removed.
you’re done.
Rewards
5 bugs - invitation to the Gecko launch party 10 bugs - the invitation, plus an attractive Gecko stuffed animal 12 bugs - the invitation, plus an attractive Gecko stuffed animal autographed by Rick Gessner, the Father of Gecko 15 bugs - the invitation, plus a Gecko T-shirt 20 bugs - the invitation, plus a Gecko T-shirt signed by the whole raptor team
the input and see if the output is still wrong.
discard the other half of the input.
Binary Search
HTML input
Simplified Input
<SELECT NAME="priority" MULTIPLE SIZE=7>
Benefits
“Printing <SELECT> crashes”.
the piece of code that prints <SELECT>.
whether they’re <SELECT>-related, too.
Why automate?
tasks.
Basic Idea
whether the failure occurs or not (= Mozilla crashes when printing or not)
binary search.
Automated Test
problem report
Binary Search ✔ ✘
<SELECT NAME="priority" MULTIPLE SIZE=7> <SELECT NAME="priority" MULTIPLE SIZE=7> <SELECT NAME="priority" MULTIPLE SIZE=7>
✔
What do we do if both halves pass?
<SELECT NAME="priority" MULTIPLE SIZE=7> ✔
✘ ✔ ✘
<SELECT NAME="priority" MULTIPLE SIZE=7> <SELECT NAME="priority" MULTIPLE SIZE=7> <SELECT NAME="priority" MULTIPLE SIZE=7>
Configuration
All circumstances
C = {δ1, δ2, . . . }
Configuration
c = {δ1, δ2, . . . δn} c ⊆ C
Circumstance
δ
Tests
test(c) ∈ {✔, ✘, ?}
Testing function
test(c✘) = ✘
Failure-inducing configuration Relevant configuration
∀δi ∈ c
✘ · testc
✘ ⊆ c✘Binary Strategy
If removing first half fails…
test(c✘ \ c1) = ✘ = ⇒ c✘ = c✘ \ c1
If removing second half fails…
test(c✘ \ c2) = ✘ = ⇒ c✘ = c✘ \ c2
Otherwise, increase granularity:
c✘ = c1 ∪ c2 ∪ c3 ∪ c4 c✘ = c1 ∪ c2 ∪ c3 ∪ c4 ∪ c5 ∪ c6 ∪ c7 ∪ c8 c✘ = c1 ∪ c2
Split input
General Strategy
Split input into n parts (initially 2)
c✘ = c1 ∪ c2 ∪ · · · ∪ cn
If some removal fails…
∃i ∈ {1, . . . , n} · test(c✘ \ ci) = ✘ = ⇒ c✘ = c✘ \ ci n = max(n − 1, 2)
Otherwise, increase granularity
c✘ = c✘ n = 2n
ddmin in a Nutshell
ddmin(c✘) = ddmin(c
✘, 2)c
✘ = ddmin(c✘) is a relevant configuration c
✘if |c
✘| = 1ddmin c
✘ \ ci, max(n − 1, 2)(“some removal fails”) ddmin c
✘, min(2n,c
✘ddmin(c
✘, n) =with
c
✘ = c1 ∪ c2 ∪ · · · ∪ cn∀ci, cj · ci ∩ cj = ∅ ∧ |ci| ≈ |cj|
where
def _ddmin(circumstances, n): while len(circumstances) >= 2: subsets = split(circumstances, n) some_complement_is_failing = 0 for subset in subsets: complement = listminus(circumstances, subset) if test(complement) == FAIL: circumstances = complement n = max(n - 1, 2) some_complement_is_failing = 1 break if not some_complement_is_failing: if n == len(circumstances): break n = min(n * 2, len(circumstances)) return circumstances
ddmin at Work
Binary Search
If
circumstance, and
circumstance fail, the number of tests is t ≤ log2(|c✘|)
More Simplification
Simplified failure-inducing fuzz input:
newline characters
Minimal Interaction
Ok the following operations cause mozilla to crash consistently on my machine
(I use the file /var/tmp/netscape.ps)
the same file (/var/tmp/netscape.ps)
Minimal Interaction
Basic idea: Apply ddmin to recorded user interaction
Delta Debugging
Delta Debugging isolates failure causes automatically: Inputs: 1 of 900 HTML lines in Mozilla Code changes: 1 of 8,721 code changes in GDB Threads: 1 of 3.8 bln thread switches in Scene.java Messages: n of m Java method calls (in progress) Fully automatic + purely test-based
Isolating Causes
double bug(double z[], int n) { int i, j; i = 0; for (j = 0; j < n; j++) { i = i + j + 1; z[i] = z[i] * (z[0] + 1.0); } return z[n]; }
Actual cause of the GCC crash
✘
defect – an error in the code.
creates an infection – an error in the state.
From Defect to Failure
✘
✘
✘ ✘ ✘
Variables
This infection chain must be traced back – and broken. t
Tracing Infections
✘
infection that causes it.
Tracing Infections
✘
Sane state Infected state
Causes in State
The difference causes GCC to crash!
Sane state Infected state
Search in Space
Mixed state
✔ ✘
Test
?
Search in Space
100 200 300 400 500 600 700 800 900 5 10 15 20 25 30 35 40 45 Deltas Tests executed Delta Debugging Log cpass cfailSearch in Space
100 200 300 400 500 600 700 800 900 5 10 15 20 25 30 35 40 45 Deltas Tests executed Delta Debugging Log cpass cfailfirst_loop_store_insn→fld[1].rtx→fld[1].rtx→ fld[3].rtx→fld[1].rtx→code == PLUS
Sane state Infected state
Search in Space
Mixed state
✔ ✘
Test
?
Sane state Infected state
Search in Space
Mixed state
✔ ✘
Test
?
<PLUS node>
Passing run Failing run
Search in Time
t
<PLUS node> <PLUS node>
Passing run Failing run
Search in Time
t
<PLUS node> <PLUS node> link→fld[0].rtx→fld[0].rtx == link
Passing run Failing run
t
<PLUS node> <Tree cycle> Transition from PLUS to cycle <PLUS node>
Search in Time
70All GCC Transitions
71 # Location Cause transition to variable Start argv[3] 1 toplev.c:4755 name 2 toplev.c:2909 dump base name 3 c-lex.c:187 finput→ IO buf base 4 c-lex.c:1213 nextchar 5 c-lex.c:1213 yyssa[41] 6 c-typeck.c:3615 yyssa[42] 7 c-lex.c:1213 last insn→fld[1].rtx →fld[1].rtx→fld[3].rtx →fld[1].rtx.code 8 c-decl.c:1213 sequence result[2] →fld[0].rtvec →elem[0].rtx→fld[1].rtx →fld[1].rtx→fld[1].rtx →fld[1].rtx→fld[1].rtx →fld[1].rtx→fld[1].rtx →fld[3].rtx→fld[1].rtx.code 9 combine.c:4271 x→fld[0].rtx→fld[0].rtxcombine.c
if (GET_CODE (XEXP (x, 0)) == PLUS { x = apply_distributive_law (gen_binary (PLUS, mode, gen_binary (MULT, mode, XEXP (XEXP (x, 0), 0), XEXP (x, 1)), gen_binary (MULT, mode, XEXP (XEXP (x, 0), 1), XEXP (x, 1)))); if (GET_CODE (x) != MULT) return x; }
Should be copy_rtx() 1 line out of 1.047.562
Implementations C Java Python
Web service + command line Eclipse plug-in Module 24 months 12 months 2 days
Code Runs Static Dynamic Future Past Prevention Cure Errors Causes
Code + Runs Static + Dynamic Future + Past Prevention + Cure Errors + Causes