Software Verification with Blast Thomas A Henzinger Ranjit
Software Verification with Blast Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar, George Necula, Grégoire Sutre, Wes Weimer UC Berkeley
Motivation Verification of systems code Locking disciplines Interface specifications Essential for correct operation High rate of bugs Temporal properties Require path-sensitive analysis Swamped by false positives Really hard to check 2
Model Checking Doesn’t scale to low level implementations Can only model check “abstractions” Requires human intervention … Abstract – Check – Refine Loop Microsoft SLAM Project [Clarke et. al. 00], [Saidi 00] 3
Abstract-Check-Refine Loop Abstraction Seed Abstraction Program Is model unsafe ? Abstract Check NO YES (Trace) Feasible Explanation Why infeasible ? Refine Infeasible SAFE BUG ? ? ? 4
Model Checking 101 Keep searching successors until … Hit error states: report “bug” ! Add no new successors: report “safe” Could take a long time … Init ERROR STATES SYSTEM’S STATE SPACE 5
Model Checking & Abstraction Problem: Far too many states Iterations don’t terminate ! Solution: Abstract … Init ERROR STATES 6
Model Checking & Abstraction Problem: Abstraction too coarse Solution: Refine abstraction Make boxes smaller Init ERROR STATES 7
Model Checking & Abstraction Problem: Abstraction too coarse Solution: Refine abstraction Make boxes smaller Init ERROR STATES 8
Abstract Only Where Required Abstraction is very expensive Why abstract regions that are never visited ? On-the-fly abstraction: driven by the search Init ERROR STATES Reachable States 9
Refine Only Where Required Why be precise everywhere ? Don’t refine error-free regions Init ERROR STATES ERROR FREE 10
Refine Only Where Required Why be precise everywhere ? Don’t refine error-free regions Different precision for different regions Local Refinement : driven by the search Init ERROR STATES ERROR FREE 11
How to improve Abstract only where required Reachable state space is very sparse Construct the abstraction on-the-fly Use greater precision only where required Different precisions/abstractions for different regions Refine locally Reuse work from earlier phases Batch-oriented ) lose work from previous runs Integrate three phases Exploit control flow structure 12
Example ( ) { 1: if (*) { 7: do { got_lock = 0; 8: if (*) { 9: lock(); got_lock ++; } 10: if (got_lock) { 11: unlock(); } 12: } while (*) ; } 2: do { lock(); old = new; 3: if (*) { 4: unlock(); new ++; } 5: } while ( new != old); 6: unlock (); return; } lock() unlock() Q: Is Error Reachable ? 13
Example: CFA Example ( ) { 1: if (*) { 7: do { got_lock = 0; 8: if (*) { 9: lock(); got_lock ++; } 10: if (got_lock) { 11: unlock(); } 12: } while (*) ; } 2: do { lock(); old = new; 3: if (*) { 4: unlock(); new ++; } 5: } while ( new != old); 6: unlock (); return; } [>] 1 2 lock(); old = new [>] 7 3 [>] 4 unlock() new++ [>] [new!=old] 5 [new==old] 6 unlock() ret 14
Example: CFA Example ( ) { 1: if (*) { 7: do { got_lock = 0; 8: if (*) { 9: lock(); got_lock ++; } 10: if (got_lock) { 11: unlock(); } 12: } while (*) ; } 2: do { lock(); old = new; 3: if (*) { 4: unlock(); new ++; } 5: } while ( new != old); 6: unlock (); return; } 1 2 7 got_lock=0 3 [>] 4 9 5 lock(); got_lock++ 8 [>] 10 [got_lock != 0] [got_lock == 0] 6 11 unlock() 12 ret [>] 15
Example: CFA Example ( ) { 1: if (*) { 7: do { got_lock = 0; 8: if (*) { 9: lock(); got_lock ++; } 10: if (got_lock) { 11: unlock(); } 12: } while (*) ; } 2: do { lock(); old = new; 3: if (*) { 4: unlock(); new ++; } 5: } while ( new != old); 6: unlock (); return; } 1 2 7 3 8 4 lock() 9 5 10 11 6 ret unlock() 12 lock() Q: Is Error Reachable ? 16
Step 1: Search 1 2 7 3 8 4 [>] 9 5 10 11 6 lock(); old = new 12 [>] 1 2 LOCK=0 3 LOCK=1 LOCK=0 ret unlock() new++ Set of predicates: 4 LOCK=1 5 LOCK=0 6 LOCK=0 Err LOCK=0 [new==old] LOCK=0, LOCK=1 unlock() 17
Step 2: Analyze Counterexample 1 2 7 3 8 4 1 9 5 2 LOCK=0 3 LOCK=1 LOCK=0 10 11 6 12 ret Q: When can: n ops 4 LOCK=1 5 LOCK=0 6 LOCK=0 Err States that can = wp( >, ops) States at node n = Rn ) check: Rn Æ wp( >, ops) = ? ? 18
Step 2: Analyze Counterexample 1 2 7 3 8 4 1 9 5 lock(); old = new 10 11 6 12 [>] LOCK=0 2 LOCK=0 Æ new+1 = new 3 LOCK=1 Æ new+1 = old ret unlock(); new++ 4 LOCK=1 Æ new +1 = old 5 LOCK=0 Æ new = old 6 LOCK=0 Err LOCK=0 [new==old] unlock() Rn Æ wp (>, ops) = ? ? 19
Step 2: Analyze Counterexample 1 2 7 3 8 4 1 9 5 lock(); old = new 10 11 6 12 [>] LOCK=0 2 LOCK=0 Æ new+1 = new 3 LOCK=1 Æ new+1 = old ret unlock(); new++ Track the predicate: new = old 4 LOCK=1 Æ new +1 = old 5 LOCK=0 Æ new = old 6 LOCK=0 Err LOCK=0 [new==old] unlock() 20
Step 3: Resume search 1 2 7 3 8 4 LOCK=0 9 5 2 10 11 6 LOCK=1 Æ new = old 12 ret 1 lock(); old = new 3 [>] LOCK=1 Æ new = old 4 LOCK=0 Æ : new = old 5 Set of predicates: LOCK=0, LOCK=1 New predicate: unlock() new++ [new==old] [new!=old] ? 6 2 LOCK=0 Æ : new = old µ LOCK =0 new = old, 21
Step 3: Resume search 1 2 7 3 8 4 LOCK=0 9 5 1 2 10 11 6 LOCK=1 Æ new = old 12 3 ret LOCK=1 Æ new = old 4 LOCK=0 Æ : new = old 5 New predicate: new = old 5 LOCK=1 Æ new=old [new!=old] [new==old] Set of predicates: LOCK=0, LOCK=1 [>] ? 6 2 6 LOCK=0 Æ : new = old 1 unlock() ? ret LOCK=0Æ new=old 22
Example: CFA Example ( ) { 1: if (*) { 7: do { got_lock = 0; 8: if (*) { 9: lock(); got_lock ++; } 10: if (got_lock) { 11: unlock(); } 12: } while (*) ; } 2: do { lock(); old = new; 3: if (*) { 4: unlock(); new ++; } 5: } while ( new != old); 6: unlock (); return; } 1 2 7 got_lock=0 3 [>] 4 9 5 lock(); got_lock++ 8 [>] 10 [got_lock != 0] [got_lock == 0] 6 11 unlock() 12 ret [>] 23
Step 4: Search Right Branch 1 2 7 3 8 4 1 [>] LOCK=0 9 5 2 LOCK=0 [>] 7 LOCK=0 10 11 6 12 ret Set of predicates: LOCK=0, LOCK=1 New predicate: (from trace) Err got_lock = 0 24
Leaves Covered (Reuse work) 1 1 2 7 3 8 4 LOCK=0 9 5 2 LOCK=0 7 LOCK=0 10 11 6 12 ret Leaves covered: Avoid repeating search when paths merge 2 2 LOCK=0 Æ … 2 COVERED ! 25
Reachability Tree LOCK=0 LOCK=1 Æ new = old LOCK=0 Æ : new = old ? 6 1 2 7 3 8 2 LOCK=0 Æ got_lock=0 9 4 5 LOCK=0 5 LOCK=1 Æ new=old 6 1 ? LOCK=1 Æ got_lock!=0 10 10 12 11 ? 11 12 ? 12 ret LOCK=0Æ new=old LOCK=0 Æ got_lock=0 2 LOCK=0 Æ got_lock=0 8 27
Invariants LOCK=0 1 Regions in the tree are invariants: 2 Invariant Inv (n) for node n = LOCK=1 Æ new = old LOCK=0 Æ : new = old ? 6 3 Disjunction of all node-n regions in the tree 4 5 2 5 LOCK=1 Æ new=old 6 1 ? Inv (5) is: LOCK=0 Æ : new = old Ç LOCK=1 Æ new=old Inv (6) is: LOCK=1 Æ new=old ret LOCK=0Æ new=old 28
Proof Generation 1 Use the invariants from the tree Verification Conditions for correctness 2 3 4 LOCK=0 Æ : new = old Ç LOCK=1 Æ new=old [new!=old] 1. Pre ) Inv (1) 2. Inv (e) = false for error node e 3. Post (Inv (j), cjk ) ) Inv (k) 4. These can be formalized as in PCC 1. Inv (1) contains Pre as disjunct 2. Error node not in tree 5 [new==old] 6 ret 29
Proof Generation II 1 Prove : Post ( Inv (i) , cij ) ) Inv (j) Use the tree to break the proof: 2 Post(AÇ B, c) ) D Ç E becomes: 3 4 LOCK=0 Æ : new = old Ç LOCK=1 Æ new=old Post (A, c) ) D and Post (B, c) ) E [new!=old] 5 Example: Post (Inv (5), new==old) ) Inv (6) [new==old] 6 Post (LOCK=0 Æ : new=old, new==old) ) LOCK=1Æ new=old Post(LOCK=1 Æ new=old, new==old) ) LOCK=1 Æ new=old ret 30
Proof Generation II 1 Prove : Post ( Inv (i) , cij ) ) Inv (j) Use the tree to break the proof: 2 Post(AÇ B, c) ) D Ç E becomes: 3 4 LOCK=0 Æ : new = old Ç LOCK=1 Æ new=old Post (A, c) ) D and Post (B, c) ) E [new!=old] 5 But these were computed in the forward search! Example: Post (Inv (5), new==old) ) Inv (6) [new==old] false ) LOCK=1Æ new=old LOCK=1 Æ new=old) LOCK=1 Æ new=old 6 ret 31
BLAST Berkeley Lazy Abstraction Software verification Tool 10 K Lines of Ocaml Analyze Linux/Windows Device Drivers CIL (C ! CFA) LAZY REGION Vampyre ABSTRACTION STRUCTURE (focus) Proof Gen Simplify BDD Engine (Post#) (Boolean ops) (PCC) 33
start NP SKIP 1 Call. Driver SKIP 2 Skip Call. Driver IPC synch MPR 3 ing nd t pe r retu ned NP MPR no completion Call. Driver MPR 1 MPR 2 prop completion PPC DC IRP accessible Mark Pending return not Pend synch N/A start P Call. Driver Complete request no prop completion return child status SKIP 1 Call. Driver N/A SKIP 2 Skip Call. Driver MPR 3 synch d rne tu g re NP in MPR end p t o completion n Call. Driver MPR 1 MPR 2 prop completion PPC IPC Call. Driver return Pending Complete request DC no prop completion N? A Call. Driver From the SLAM project 34
Experiments Windows Drivers (IRP Spec – 22 states) Program Lines Predicates Time Proof floppy. c 17386 62 37 35 min 17386 93 44 21 min 60 K parport. c 61781 193 50 33 min 103 K mouclass. c cdaudio. c kbfiltr. c 17352 57 46 1 min 17798 85 45 23 min 12131 54 40 1 min 12131 12 8 10 sec 156 K 7 K 35
Experiments : Linux Locking Program Lines Predicates Time Proof ide. c 18131 5 5 4 sec 253 aironet. c 18152 17 11 4 min aha 152 x. c 17736 2 2 20 sec tlan. c 16505 5 4 7 min 405 36
Why Abstract Lazily ? Reach set is very sparse Abstract on-the-fly Only the reachable region Requires very fast post# Exploit Control-Flow Structure Free partitioning of state space Partition preds: different abstractions Refine locally: don’t repeat old work 37
Problems/Future work Engineering Issues Program analysis Partitioning by partial evaluation Theory of counterexample driven refinement for all linear and branching time logics 38
“BLAST! This is why I hate flying!” - Jedi Master Obi-Wan Kenobi in Episode II: Attack of the Clones, 2002 44
- Slides: 37