610 likes | 633 Views
This article discusses the use of lazy abstraction for scalable program verification, highlighting its application in detecting bugs and failures in software systems. It presents relevant case studies and dives into the contributions and advancements made in the field.
E N D
Scalable Program Verification by Lazy Abstraction Ranjit Jhala U.C. Berkeley
Mars, July 4, 1997 Lost contact due to real-time priority inversion bug Mars, December 3, 1999 Crashed due to uninitialized variable
French Guyana, June 4, 1996 $600 million software failure
Something Reliable Uptime: 67 years
Why don’t Bridges Crash ? Abstraction Bridges Programs Building Blocks Logic Mechanics • Relevant facts* • Model • Analysis Mass, Tensile Strength Free Body Diagram Solve Equations ? ? ? * w.r.t. property of interest
Contributions Yes BLAST Safe Search CProgram [POPL 02] Refine No Property Property [POPL 04] Trace
lock unlock unlock lock Property 1: Double Locking “An attempt to re-acquire an acquired lock or release a released lock will cause a deadlock.” Calls to lock and unlock must alternate.
Property 2: Drop Root Privilege [Chen-Dean-Wagner ’02] “User applications must not run with root privilege” When execv is called, must have suid 0
start NP CallDriver SKIP1 SKIP2 return child status Skip CallDriver IPC synch MPR3 NP CallDriver prop completion PPC not pending returned MPR completion Complete request CallDriver MPR1 MPR2 DC return not Pend no prop completion synch CallDriver N/A N/A IRP accessible CallDriver start P SKIP2 Mark Pending SKIP1 Skip CallDriver IPC synch MPR3 NP CallDriver prop completion return Pending PPC not pending returned MPR completion Complete request CallDriver MPR1 MPR2 DC no prop completion CallDriver N/A Property 3 : IRP Handler [Fahndrich]
A data race on x is a state where: Two threads can access x One of the accesses is a write There should be no races on shared variables Property 4: Data Races x:= x+1 x:= x-5 x
Yes Safe Contributions Program BLAST No Property Trace Sequential Programs Counterex.-Guided Abstraction-Refinement For large programs, complex properties New Algorithms: Abstraction[POPL 02],Refinement[POPL 04] Property 1: Double Locking (Linux/Windows Drivers) Property 2: Drop Root Privilege (Linux Daemons ~59kloc) • Precise: No false Errors Property 3: IRP Handler (NT Drivers ~130Kloc) • Large Programs
Yes Safe Contributions Program BLAST No Property Trace Multithreaded Programs New models for thread interactions New algorithms to compute models and Verify multithreaded programs [CAV 03] [PLDI 04] Property 4: Data Races • Linux/Windows Drivers • Sensor Network Apps. (TinyOS/NesC) ~10kloc • Arbitrarily many threads • Any synchronization mechanisms • Real counterexamples, Safety Proofs
Plan • C.G. Abstraction-Refinement • Lazy Abstraction • Sequential Programs • Multithreaded Programs • Future Work
lock unlock unlock lock Example Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4: } while(new != old); 5: unlock (); return; }
pc lock old new q 3 5 5 0x133a pc lock old new q 4 5 6 0x133a What a program really is… State Transition 3: unlock(); new++; 4:} … Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4: } while(new != old); 5: unlock (); return;}
The Safety Verification Problem Error Safe Initial Is there a path from an initial to an error state ? Problem:Infinitestate graph Solution : Set of states ' logical formula
Idea 1: Predicate Abstraction • Predicates on program state: lock old = new • States satisfying same predicates are equivalent • Merged into one abstract state • #abstract states is finite [Graf-Saidi 97]
pc lock old new q 3 5 5 0x133a pc lock old new q 4 5 6 0x133a Abstract States and Transitions State 3: unlock(); new++; 4:} … Theorem Prover lock old=new : lock : old=new
pc lock old new q 3 5 5 0x133a pc lock old new q 4 5 6 0x133a Abstraction State 3: unlock(); new++; 4:} … Theorem Prover lock old=new : lock : old=new Existential Lifting
pc lock old new q 3 5 5 0x133a pc lock old new q 4 5 6 0x133a Abstraction State 3: unlock(); new++; 4:} … lock old=new : lock : old=new
Analyze Abstraction Analyze finite graph Over Approximate: Safe ) System Safe No false negatives Problem Spurious counterexamples
Idea 2: Counterex.-Guided Refinement Solution Use spurious counterexamples to refine abstraction! [Kurshan et al 93] [Clarke et al 00] [Ball-Rajamani 01]
Idea 2: Counterex.-Guided Refinement Solution Use spurious counterexamples to refine abstraction 1. Add predicates to distinguish states across cut 2. Build refined abstraction Imprecision due to merge [Kurshan et al 93] [Clarke et al 00] [Ball-Rajamani 01]
Iterative Abstraction-Refinement Solution Use spurious counterexamples to refine abstraction 1. Add predicates to distinguish states across cut 2. Build refined abstraction -eliminates counterexample 3. Repeat search Till real counterexample or system proved safe [Kurshan et al 93] [Clarke et al 00] [Ball-Rajamani 01]
Plan 1. C.G. Abstraction-Refinement 2. Lazy Abstraction • Sequential Programs [POPL 02] [POPL04] • Multithreaded Programs 3. Future Work
Scaling Sequential Verification Yes BLAST Safe Abstract CProgram [POPL 02] Refine No Property [POPL 04] Trace
Problem: Abstraction is Expensive Reachable Problem #abstract states = 2#predicates Exponential Thm. Prover queries Observe Fraction of state space reachable #Preds ~ 100’s, #States ~ 2100 , #Reach ~ 1000’s
Solution1: Only Abstract Reachable States Safe Solution Build abstraction during search Problem #abstract states = 2#predicates Exponential Thm. Prover queries
Solution2: Don’t Refine Error-Free Regions Error Free Solution Don’t refine error-free regions Problem #abstract states = 2#predicates Exponential Thm. Prover queries
Key Idea: Reachability Tree Initial Unroll Abstraction 1. Pick tree-node (=abs. state) 2. Add children (=abs. successors) 3. On re-visiting abs. state, cut-off 1 2 3 Find min infeasible suffix - Learn new predicates - Rebuild subtree with new preds. 5 4 3
Key Idea: Reachability Tree Initial Unroll Abstraction 1. Pick tree-node (=abs. state) 2. Add children (=abs. successors) 3. On re-visiting abs. state, cut-off 1 2 3 6 Find min infeasible suffix - Learn new predicates - Rebuild subtree with new preds. 4 7 5 3 3 Error Free
Key Idea: Reachability Tree Initial Unroll 1. Pick tree-node (=abs. state) 2. Add children (=abs. successors) 3. On re-visiting abs. state, cut-off 1 2 3 6 Find min spurious suffix - Learn new predicates - Rebuild subtree with new preds. 4 7 8 5 8 3 1 1 3 Error Free S1: Only Abstract Reachable States S2: Don’t refine error-free regions SAFE
Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 1 Reachability Tree Predicates:LOCK
Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK lock() old = new q=q->next 2 LOCK 1 2 Reachability Tree Predicates:LOCK
Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 2 LOCK [q!=NULL] 3 LOCK 1 2 3 Reachability Tree Predicates:LOCK
Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 2 LOCK 3 LOCK q->data = new unlock() new++ 4 : LOCK 4 1 2 3 Reachability Tree Predicates:LOCK
Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 2 LOCK 3 LOCK 4 : LOCK [new==old] 5 : LOCK 5 4 1 2 3 Reachability Tree Predicates:LOCK
Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 2 LOCK 3 LOCK 4 : LOCK 5 : LOCK 5 unlock() 4 : LOCK 1 2 3 Reachability Tree Predicates:LOCK
Analyze Counterexample Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK lock() old = new q=q->next 2 LOCK [q!=NULL] 3 LOCK q->data = new unlock() new++ 4 : LOCK [new==old] 5 : LOCK 5 unlock() 4 : LOCK 1 2 3 Reachability Tree Predicates:LOCK
Analyze Counterexample Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK old = new 2 LOCK 3 LOCK new++ 4 : LOCK [new==old] 5 : LOCK 5 Inconsistent 4 : LOCK new == old 1 2 3 Reachability Tree Predicates:LOCK
Repeat Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 1 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK lock() old = new q=q->next 2 LOCK , new==old 1 2 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 2 LOCK , new==old 3 LOCK , new==old q->data = new unlock() new++ 4 : LOCK , : new = old 4 1 2 3 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 2 LOCK , new==old 3 LOCK , new==old 4 : LOCK , : new = old [new==old] 4 1 2 3 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 2 LOCK , new==old 3 LOCK , new==old 4 : LOCK , : new = old [new!=old] 1 : LOCK, : new == old 4 4 1 2 3 Reachability Tree Predicates:LOCK, new==old
Repeat Build-and-Search Example ( ) { 1: do{ lock(); old = new; q = q->next; 2: if (q != NULL){ 3: q->data = new; unlock(); new ++; } 4:}while(new != old); 5: unlock (); } 1 : LOCK 2 LOCK , new==old SAFE 3 LOCK , new==old 4 4 LOCK , new=old : LOCK , : new = old 1 5 5 : LOCK, : new == old 4 4 4 1 : LOCK , new==old 2 3 Reachability Tree Predicates:LOCK, new==old
Scaling Sequential Verification Yes Safe Abstract CProgram [POPL 02] Refine No Property Trace Problem:Abstraction is Expensive Solution:1.Abstract reachable states, 2. Avoid refining error-free regions Key Idea: Reachability Tree
Property3: IRP Handler Win NT DDK Results * Pre-processed
Analyzing Programs Abstraction Programs Building Blocks Logic • Relevant facts* • Model • Analysis Predicates Reach Tree Search * w.r.t. property of interest
Plan • C.G. Abstraction-Refinement • Lazy Abstraction • Sequential Programs [POPL 02, POPL 04] • Multithreaded Programs • Future Work