560 likes | 802 Views
Thomas Ball Sriram K. Rajamani. http://research.microsoft.com/slam/ http://msrweb/slam. Checking API Usage. Application. Does an application follow the “proper usage” rules of an API?. API. C lib | DLL | COM |…. One Application: W2k Device Drivers. Device Driver.
E N D
Thomas Ball Sriram K. Rajamani http://research.microsoft.com/slam/ http://msrweb/slam
Checking API Usage Application Does an application follow the “proper usage” rules of an API? API C lib | DLL | COM |…
One Application: W2k Device Drivers Device Driver Does a device driver acquire and release spin locks properly? IO Manager API NT Kernel
Device Drivers and SLAM Device Driver IO Manager Interface API Rules (SLIC)
State MachineFor Locking state { int locked = 0; } Lock.call { if (locked==1) abort; else locked = 1; } UnLock.call { if (locked==0) abort; else locked = 0; } U L Unlocked Locked Error L U
State MachineFor Irp Handling init IoMarkIrpPending IoCompleteRequest pending complete return:status != STATUS_PENDING return: status == STATUS_PENDING Error
IRP Complete/Pending Rule state { enum {Init, Complete, Pending} s = Init; } IoCompleteRequest.call{ if ( s != Init) abort; else s = Complete; } IoMarkIrpPending.call{ if( s != Init) abort; else s = Pending; } Dispatch.exit{ if (s == Complete) { if ($return == STATUS_PENDING) abort; } else if (s == Pending) { if( $return != STATUS_PENDING) abort; } }
Goal: Run the state machine through all paths in the program Problem: Too many paths! Solution: State based search Problem : False alarms! Solution : Better abstraction
False alarm do { KeAcquireSpinLock(); nPacketsOld = nPackets; if(request){ request = request->Next; KeReleaseSpinLock(); nPackets++; } } while (nPackets != nPacketsOld); KeReleaseSpinLock();
False alarm do { KeAcquireSpinLock(); nPacketsOld = nPackets; if(request){ request = request->Next; KeReleaseSpinLock(); nPackets++; } } while (nPackets != nPacketsOld); KeReleaseSpinLock();
False alarm do { KeAcquireSpinLock(); nPacketsOld = nPackets;b := true; if(request){ request = request->Next; KeReleaseSpinLock(); nPackets++; b := b? false : *; } } while (nPackets != nPacketsOld); KeReleaseSpinLock();
False alarm do { KeAcquireSpinLock(); nPacketsOld = nPackets;b := true; if(request){ request = request->Next; KeReleaseSpinLock(); nPackets++; b := b? false : *; } } while (nPackets != nPacketsOld); KeReleaseSpinLock(); b b b b !b b b
False alarm do { KeAcquireSpinLock(); nPacketsOld = nPackets;b := true; if(request){ request = request->Next; KeReleaseSpinLock(); nPackets++; b := b? false : *; } } while (nPackets != nPacketsOld); KeReleaseSpinLock(); b b b b !b b b
C program Spec. SLIC GOLF predicates Boolean program CFG + VFG c2bp bebop predicates Pass newton Fail, p GUI Error
Key Ideas Inexpensive whole program analysis (GOLF) Local abstraction step to produce an abstraction for the property of interest (c2bp) State-based search on the abstraction (bebop) Automated refinement of abstractions (newton)
Bebop • Performs reachability analysis of boolean programs • Symbolic version of [Reps-Horwitz-Sagiv, POPL’95] interprocedural data flow analysis • Explicit representation of control flow • Implicit representation of reachable states via BDDs • Complexity of algorithm is O( E 2n) E = size of interprocedural control flow graph n = max. number of variables in the scope of any label
c2bp: Automatic Predicate Abstraction of C • What is the predicate language? • Pure C boolean expressions • Input: a C program P and set of predicates E • Output: a boolean program c2bp(P,E) that is • a sound abstraction of P • a precise abstraction of P • Difficulties • procedures • pointers
C2bp Philosophy • Computing a precise Boolean abstraction is • too expensive • unnecessary for C • deterministic concrete semantics • Exploit ideas from program analysis and symbolic model checking • Off-line computation of abstract transfer function • Attribute (predicate) independence • Disjunctive completion • Focus operation • Static partitioning of states by control points • Implicit representation of stack in boolean program
c2bp(P,E) Predicates in E: e : (nPacketsOld==nPackets) Statement in P: s : nPackets = nPackets+1; Weakest Precondition: pre(s,e): nPacketsOld==nPackets+1 Strengthened WP: F(pre(s,e)): false
c2bp(P,E) Predicates in E: e : (nPacketsOld==nPackets) Statement in P: s : nPackets = nPackets+1; Weakest Precondition: pre(s,!e): !(nPacketsOld==nPackets+1) Strengthened WP: F(pre(s,!e)): e
c2bp(P,E) In general, given statement s and predicates { e1 ,…, en }: {e1},…,{en} := choose(F(pre(s,e1),F(pre(s,!e1))), …, choose(F(pre(s,en),F(pre(s,!en))); O(2n*2n) O(2n*nc) bool choose(bool pos,bool neg) = true if pos=true false if neg=true * pos=neg=false choose not well defined for pos=neg=true
WP and pointers Predicates in E: e : (x==2) Statement in P: s : *p = *p + 1 WP: WP(s,e): x==2 ???
Morris’ Axiom ofAssignment Predicates in E: e : (x==2) Statement in P: s : *p = *p + 1 WP: WP(s,e): ((p!=&x) and x==2) or ((p==&x) and x==1)
WP and pointers Predicates in E: e : (x==2) Statement in P: s : *p = *p + 1 WP: WP(s,e): x==2 if we can show p can never point to x, using points-to-analysis
c2bp • Processes one statement at a time • Assignments, conditionals, procedure call/return • Computes WP and strengthens it • theorem prover (Simplify,Vampyre) • Alias queries • one-level flow flow-insensitive PTA of Das [PLDI’00]
c2bp Soundness: • have to consider aliasing • have to consider side effects of procedure calls [Ball-Majumdar-Millstein-Rajamani PLDI 01] [Ball-Millstein-Rajamani, Tech-report] Precision: • formalized declaratively as an abstract interpretation [Ball-Podelski-Rajamani TACAS 01]
On-line Abstraction:State = Bit Vector b n post k b each abstract step during model checking requires O(2n) theorem prover queries
On-line Abstraction:Set of States = Single Tri-vector b c post b c each abstract step during model checking cbrequires O(2n) theorem prover queries
SLAM - Off-line Abstraction:Set of States = Set of Tri-vectors bebop c2bp each abstract step during model checking requires O(2n*k) operations, k=O(2n )
c2bp Number of theorem prover calls: • Worst case : O(|P| . 2|E|) • Practice: O(|P|. |E|3)
Newton • Symbolically executes (interprocedural) path in C program • Checks for path infeasibility using decision procedures • If infeasibility detected • Minimizes inconsistent conditions • Obtains new predicates
Example Store: nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions:
Example Store: nPacketsOld: nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions:
Example Store: nPacketsOld: nPackets: (1) nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions:
Example Store: nPacketsOld: nPackets: (1) devExt: nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions:
Example Store: nPacketsOld: nPackets: (1) devExt: ->WLHeadVa: (3) nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions:
Example Store: nPacketsOld: nPackets: (1) devExt: ->WLHeadVa: (3) request: (3,4) nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions:
Example Store: nPacketsOld: nPackets: (1) devExt: ->WLHeadVa: (3) request: (3,4) nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions: ! (5)
Example Store: nPacketsOld: nPackets: (1) devExt: ->WLHeadVa: (3) request: (3,4) nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions: ! (5) != (1,2)
Example Store: nPacketsOld: nPackets: (1) devExt: ->WLHeadVa: (3) request: (3,4) nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions: != (1,2)
Example Store: nPacketsOld: nPackets: (1) nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Conditions: != (1,2)
Example Predicates: (nPacketsOld == ) (nPackets == ) ( != ) nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld);
Example nPackets = nPacketsOld; request = devExt->WLHeadVa; assume(!request); assume(nPackets != nPacketsOld); Predicates: (nPacketsOld != nPackets)
Example (2) Store: assume(x > y); y := y - 1; assume ( !(x > y)); Conditions:
Example (2) Store: x : (2) y : assume(x > y); y := y - 1; assume ( !(x > y)); Conditions: > (1,2)
Example (2) Store: x : (3) y : - 1 (2) assume(x > y); y := y - 1; assume ( !(x > y)); History: (2) y : Conditions: > (1,2)
Example (2) Store: x : (3) y : - 1 (2) assume(x > y); y := y - 1; assume ( !(x > y)); History: (2) y : Conditions: > (1,2) !( > -1 ) (1,3)
Example (2) assume(x > y); y := y - 1; assume ( !(x > y)); Predicates: y == y == - 1 x >
Related Work • VCGen based tools • ESC-Java [Leino-Nelson-et al.] • Proof-Carrying Code [Lee-Necula] • PREfix [Pincus-et al.] • Model Checking of Software • Using an abstract model • Bandera [Hatcliff-Dwyer-et al.] • FeaVer [Holzmann] • FLAVERS [Clarke-Osterweil-et al.] • Metal [Engler] • By gaining control over the scheduler • Java Path Finder [Visser-et al.] • Verisoft [Godefroid] • Java model checker [Stoller]