230 likes | 379 Views
Dual Analysis for Proving Safety and Finding Bugs. Corneliu Popeea Wei-Ngan Chin Technische Universität M ü nchen National University of Singapore. Symposium on Applied Computing – SAC 2010, Sierre, Switzerland. Why do Program Analysis?. Programs have bugs Program analysis for
E N D
Dual Analysis forProving Safety and Finding Bugs Corneliu Popeea Wei-Ngan Chin Technische Universität München National University of Singapore Symposium on Applied Computing – SAC 2010, Sierre, Switzerland
Why do Program Analysis? Programs have bugs Program analysis for • proving safety • finding bugs
Automated Approaches • Program testing: • detects presence of bugs • examines some paths, not all(under-approximation of the program semantics) • compromises on program safety • Verification: • examines all paths(over-approximation of the program semantics) • may report false bugs
Combination of Testing and Verification • Search for both bugs and safety proofs • Combination of under- and over-approximation • Projects at Microsoft Research • Synergy, Smash: analysis of Windows device drivers
Our Methodology • Extend a static analyzer aimed at proving safety to discover (true) bugs • based only on over-approximation analysis • dual simultaneous analyses
Quicksort Example void quicksort (float a[], int l, int h) { if (l < h) { int p = partition (a,l,h); quicksort (a,l,p-1); quicksort (a,p+1,h); }} int partition (…) { … v = a[l]; … a[m] = v; …} WANTED 2 conditions on inputs a,I,h NeverBug - guarantees safety of bound checks MustBug - guarantees execution triggers a bug
OK ERR Concrete Semantics and Abstraction • Three possible outcomes for a program execution: ok - for a safe/successful execution err - for an unsafe execution (due to a failed assertion) loop - for a non-terminating execution • Compute over-approximations for inputs leading to: OK - all possibly safe executions ERR - all possibly unsafe executions • Example: OK=true, ERR=true
Forward Reasoning Rules • Formulated using Hoare-style triples: • Rule for function call: • Summaries of recursive functions: • computed by abstract interpretation
Partial correctness Bug finding OK ERR Partial Correctness and Bug Finding • NEVER_BUG = OK Æ:ERR Any input satisfying this condition is guaranteed to lead to ok or loop. • MUST_BUG = ERR Æ:OK Any input satisfying this condition is guaranteed to lead to err or loop. • MAY_BUG = OK Æ ERR Any input satisfying this condition may lead to either ok , err or loop. NEVERBUG MUSTBUG MAYBUG
Quicksort Example void quicksort (float a[], int l, int h) { … } Compute OK and ERR using a disjunctive abstract domain: Characterization of quicksort inputs: NEVER_BUG = OK MUST_BUG = ERR
LOOP OK ERR Detect Non-termination • Some inputs may be outside both OK and ERR.LOOP = :OK Æ:ERR Any input satisfying this condition is guaranteed to lead to loop. • Example: void ex_fig9() { int x,y; x:=0; y:=0; l5: while (y>=0) {y:=y+x;} l6: assert(false); } • Loop summary: {OK: (x<0 Ç y<0), ERR: false • Function summary: {OK: false, ERR.l5.LOOP: true, ERR.l6: false} , LOOP: (x¸0 Æ y¸0)} }
Dualyzer: Prototype Implementation • Written in the Haskell language: • uses a Presburger arithmetic solver: Omega library • disjunctive fixed-point analyzer • Objectives: • prove program safety + confirm true bugs • Test programs: • small programs: binary search, queens, quick sort • numerical benchmarks: Fast Fourier Transform, LU decomposition, Linpack
Correct programs: can prove safety of bound checks? Faulty programs:can identify true bugs? Dualyzer and Blast [Henzinger-Jhala-et-al POPL02]
Verisec Benchmark [Ku-Hart-Chechik-Lie ASE07] • Small challenging testcases: • actual vulnerabilities from CVE database • corrected versions of these testcases • Dualyzer found 2 unknown bugs in the corrected testcases: • off-by-one buffer error [SpamAssassin testcase] • non-termination bug [Samba testcase]
Related Work • Static analysis / Program testing / Model checking. • Various goals: • proving safety. • finding bugs. • proving safety + finding bugs. • A bug that is reported indicates: • a true bug (unconditionally): bugs • either a true bug or a false positive: bugs(1) • a true bug, or non-termination: bugs(2)
Conclusion • Dual analyses based on over-approximation • prove program safety • find bugs • Find non-termination inputs • Prototype implementation
Example void g(int[] a, ref int x) { if (x<=0) then () else { a[x]:=0; //assert(0 <= x < a) x:=x-1; g(a,x) }}
For general recursion, the ERR cons-abs. may depend on OK. OK ERR Constraint Abstractions - Dual Analysis void g(int[] a, ref int x) { if (x<=0) then () else { a[x]:=0; x:=x-1; g(a,x) }} • Constraint abstractions: gOK(a,x,x') = (x·0 Æ x'=x) Ç (x>0 Æ 0·x<aÆ9x1¢(x1=x-1Æ gOK(a,x1,x'))) gERR(a,x) = x>0 Æ (x<0 Ç x¸a Ç 0·x<a Æ9x1¢(x1=x-1 Æ gERR(a,x1))) • Results of fixpoint approximation: gOK(a,x,x') = (x·0Æx'=x) Ç (1·x < a Æx'=0) gERR(a,x) = (x>0 Æ x¸a) • Function summary: {gOK, gERR}.
Report the label of calls that lead to a bug void foo(int x, int y) { if x=y then { l3: error } else () } void goo(int x) { l1: foo(x,x+1); l2: foo(x,3); } OK ERR.l2.l3 ERR.l1.l3 Precise Error Tracing {OK: x y, ERR.l3: x=y} {OK: x 3, ERR.l1.l3: false, ERR.l2.l3: x=3}
Examples from SYNERGY [Gulavani-et-al FSE06] Synergy: software model checker + testing • discovers a true BUG; • proves that the program is SAFE; • times-out during refinement loop (ABORT).
Related Work • Static analysis / Program testing / Model checking.