550 likes | 658 Views
Path Invariants or “How To Decompose Your Program Analysis”. Tom Henzinger EPFL. Joint work with Dirk Beyer, Rupak Majumdar, and Andrey Rybalchenko (PLDI 2007). Abstraction in Program Verification.
E N D
Path Invariantsor“How To Decompose Your Program Analysis” Tom Henzinger EPFL Joint work with Dirk Beyer, Rupak Majumdar, and Andrey Rybalchenko (PLDI 2007).
Abstraction in Program Verification 1 Abstract interpretation [Cousot & Cousot 77] 2 Automation using theorem proving [Graf & Saidi 96] 3 Refinement using counterexamples [Kurshan, Clarke et al.] Tools: Slam/SDV [Microsoft] Blast [UC Berkeley] Magic [CMU] FSoft [NEC] etc.
Model Checking for Safety counterexample: path to defect defects program transition: x’ = x+1 program state: x = 10, y = 20, a[0] = 1, a[1] = 3, ...
Concrete Reachability Safety: ReachÅDefects = ; Incremental computation: Start–initial state Next –transition relation Reach = Start [ Next(Start) [ Next2(Start) [ ... large/infinite number of iterations required
Abstract Reachability Abstraction: equivalence relation on states with finite index Abstract transition relation: [Next] [Reach] = [Start] [ [Next]([Start]) [ [Next]2([Start]) [ ... [ [Next]N([Start]) [Reach]ÅDefects = ; program is safe
Abstraction Refinement • too coarse abstraction leads to spurious counterexamples • refinement by finer partitioning spurious transition real counterexample= bug report
Abstract-Check-Refine Loop Program + Property Build Abstraction Refined Abstraction Concretize Error Trace Model Check Abstraction Abstract Error Trace Concrete Error Trace Correctness Proof (ART)
do { KeAcquireSpinLock(); nPacketsOld = nPackets; req = devExt-WLHV; if (req && req->status) { devExt->WLHV = req->Next; KeReleaseSpinLock(); irp = req->irp; if (req->status > 0) { irp->IoS.Status = SUCCESS; irp->IoS.Info = req->Status; } else { irp->IoS.Status = FAIL; irp->IoS.Info = req->Status; } SmartDevFreeBlock(req); IoCompleteRequest(irp); nPackets++; } } while (nPackets != nPacketsOld); KeReleaseSpinLock();
Simplified Version Example () { 1: do { lock (); old = new; 2: if (*) { 3: unlock (); new ++; } 4: } while (new != old); 5: unlock (); ?: return; } lock () U L unlock () unlock () lock () E Safety monitor
1 lock (); old = new 2 lock () U L [T] [T] unlock () 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Control Flow Graph Example () { 1: do { lock (); old = new; 2: if (*) { 3: unlock (); new ++; } 4: } while (new != old); 5: unlock (); ?: return; }
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Abstract Reachability 1 U
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Abstract Reachability 1 U lock (); old = new 2 L
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Abstract Reachability 1 U lock (); old = new 2 L [T] 3 L unlock (); new++ 4 U
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Abstract Reachability 1 U lock (); old = new 2 L [T] 3 L unlock (); new++ 4 U [new == old] 5 U
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Counterexample Path 1 U lock (); old = new 2 L [T] 3 L unlock (); new++ 4 U [new == old] 5 U unlock () ? E
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Path Formula 1 U new2 = old1Æ new4 = new2 + 1 Æ new4 = old1 lock (); old = new 2 L [T] 3 L unlock (); new++ 4 U [new == old] 5 U unlock () ? E
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Path Formula 1 U new2 = old1Æ new4 = new2 + 1 Æ new4 = old1 lock (); old = new 2 L [T] 3 L Unsatisfiable) counterexample spurious unlock (); new++ 4 U [new == old] 5 U unlock () ? E
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Path Formula 1 U new2 = old1Æ new4 = new2 + 1 Æ new4 = old1 lock (); old = new 2 L [T] 3 L new = old is a relevant predicate unlock (); new++ 4 U [new == old] 5 U unlock () ? E
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Refined Abstract Reachability 1 U lock (); old = new 2 L, new = old
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Refined Abstract Reachability 1 U lock (); old = new 2 L, new = old [T] L, new = old 3 unlock (); new++ U, new old 4
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Refined Abstract Reachability 1 U lock (); old = new 2 L, new = old [T] L, new = old 3 unlock (); new++ U, new old 4 [new == old] 5
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Refined Abstract Reachability 1 U lock (); old = new 2 L, new = old [T] L, new = old 3 unlock (); new++ U, new old 4 [new == old] [new != old] 5 1 U, new old
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Refined Abstract Reachability 1 U covered lock (); old = new 2 L, new = old [T] L, new = old 3 unlock (); new++ U, new old 4 [new == old] [new != old] 5 1 U, new old
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Complete Abstract Reachability Tree (ART) 1 U lock (); old = new 2 L, new = old [T] [T] L, new = old 3 4 L, new = old [new != old] unlock (); new++ [new == old] 1 5 L, new = old U, new old 4 unlock () [new == old] [new != old] 5 1 ? U, new = old U, new old
1 lock (); old = new 2 lock () U L [T] unlock () [T] 3 [new != old] unlock () lock () unlock (); new++ 4 E [new == old] 5 unlock () ? Complete ART = Proof of Correctness Inductive invariant: (pc=2 ! new=old) Æ (pc=3 ! new=old) Æ … 1 U lock (); old = new 2 L, new = old [T] [T] L, new = old 3 4 L, new = old [new != old] unlock (); new++ [new == old] 1 5 L, new = old U, new old 4 unlock () [new == old] [new != old] 5 1 ? U, new = old U, new old
“Lazy, Parsimonious Abstraction” • Constructing abstract transition relation is expensive: build ART • Track relevant predicates locally: only along spurious counterexamples
“Lazy, Parsimonious Abstraction” • Constructing abstract transition relation is expensive: build ART • Track relevant predicates locally: only along spurious counterexamples Not limited to predicate abstraction: lazy shape analysis (CAV 07), predicated lattices [Fisher, Jhala & Majumdar], etc.
Problem: Program Loops 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n );
First Counterexample Path 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 1 2 4 1 5 [a+b != 3*n] E
Path Formula 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 i1=0 Æ a1=0 Æ b1=0 Æ i1n0Æ a2 = a1+1 Æ b2 = b1+2 Æ i4=i1+1 Æ i4=n0Æ a2 + b2 3n0 1 2 4 1 5 [a+b != 3*n] E
Path Formula 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 i1=0 Æ a1=0 Æ b1=0 Æ i1n0Æ a2 = a1+1 Æ b2 = b1+2 Æ i4=i1+1 Æ i4=n0Æ a2 + b2 3n0 1 2 4 1 Unsatisfiable: track i=0, i=1, a=0, a=1, b=0, b=2, n=1 5 [a+b != 3*n] E
ART 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 1 i=0, a=0, b=0 2 i=0, a=0, b=0 4 i=0, a=1, b=2 1 i=1, a=1, b=2 5 i=1, a=1, b=2, n=1 [a+b != 3*n] E
Second Counterexample Path 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 2 i=1, a=1, b=2 1 4 i=1 2 1 4 5 1 i=1, a=1, b=2 5 i=1, a=1, b=2, n=1 [a+b != 3*n] E
Second Counterexample Path 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 2 i=1, a=1, b=2 1 4 i=1 2 1 4 5 [a+b != 3*n] 1 E 5
Second Counterexample Path 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 2 i=1, a=1, b=2 1 4 i=1 2 1 4 5 [a+b != 3*n] 1 E 5 Track also: i=2, a=2, b=4, n=2
k-th Counterexample Path 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); Track: i=0, i=1, … i=k, a=0, a=1, … a=k, b=0, b=1, … b=2k, n=k Refinement does not terminate.
Solution Viewcounterexamples not as paths, but as programs!
Solution Viewcounterexamples not as paths, but as programs! Path program: smallest fragment of the original program that contains a given path. Counterexample: path program that contains a given counterexample path.
Counterexample = Path Program 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 i=0; a=0; b=0 [i != n] 2 a=a+1; b=b+2 1 4 i=i+1 [i == n] 5 [a+b != 3*n] E
Counterexample Path Invariants 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 i=0; a=0; b=0 a+b=3i [i != n] 2 a=a+1; b=b+2 1 a+b=3i 4 i=i+1 [i == n] a+b=3i+3 5 a+b=3i Æ i=n [a+b != 3*n] E
Path Invariants Tracking path invariants removes all spurious counterexample paths that lie within the path program!
Path Invariants Tracking path invariants removes all spurious counterexample paths that lie within the path program! Path invariants can be constructed by any method for invariant synthesis [Karr, Cousot & Halbwachs, Manna et al., Kapur et al., etc.]. Path programs are small fragments of the original program, so there is hope that invariant synthesis can be automated.
ART 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 2 a+b=3i i=0; a=0; b=0 4 a+b=3i+3 1 a+b=3i 1 a+b=3i a+b=3i, i=n 5 E
Complete ART 0: i = 0; a = 0; b = 0; 1: while( i != n ) { if (*) { 2: a = a+1; b = b+2; } else { 3: a = a+2; b = b+1; } 4: i = i+1; } 5: assert( a+b == 3*n ); 0 2 a+b=3i i=0; a=0; b=0 4 a+b=3i+3 1 a+b=3i 1 a+b=3i 3 a+b=3i a+b=3i, i=n 5 4 a+b=3i+3 E 1 a+b=3i
Quantified Invariants 0: for( i=0; i<n; i++) { 1: a[i] = 0; } 2: for( i=0; i<n; i++) { 3: assert( a[i] == 0 ); }
First Counterexample Path 0 0: for( i=0; i<n; i++) { 1: a[i] = 0; } 2: for( i=0; i<n; i++) { 3: assert( a[i] == 0 ); } 1 0 Track a[0]=0 2 3 E
k-th Counterexample Path 0: for( i=0; i<n; i++) { 1: a[i] = 0; } 2: for( i=0; i<n; i++) { 3: assert( a[i] == 0 ); } Track a[k]=0
Counterexample Path Program 0: for( i=0; i<n; i++) { 1: a[i] = 0; } 2: for( i=0; i<n; i++) { 3: assert( a[i] == 0 ); } 0 1 2 3 E
Counterexample Path Invariants 8 k: 0·k<i ! a[k]=0 8 k: 0·k<i ! a[k]=0 0: for( i=0; i<n; i++) { 1: a[i] = 0; } 2: for( i=0; i<n; i++) { 3: assert( a[i] == 0 ); } 0 1 2 3 8 k: 0·k<n ! a[k]=0 8 k: 0·k<n ! a[k]=0 E
Counterexample Path Invariants 8 k: 0·k<i ! a[k]=0 8 k: 0·k<i ! a[k]=0 0: for( i=0; i<n; i++) { 1: a[i] = 0; } 2: for( i=0; i<n; i++) { 3: assert( a[i] == 0 ); } 0 1 2 3 8 k: 0·k<n ! a[k]=0 8 k: 0·k<n ! a[k]=0 E Quantified invariants can be synthesized in the combined theory of linear arithmetic and uninterpreted functions (VMCAI 07).