thomas ball sriram k. rajamani
TRANSCRIPT
Thomas BallSriram K. Rajamani
http://research.microsoft.com/slam/http://msrweb/slam
Checking API Usage
Application
C lib | DLL |
COM |…
API
Does an application follow the “proper usage” rules of an API?
One Application: W2k Device Drivers
Device Driver
NT Kernel
IO Manager API
Does a device driver acquire and release spin locks properly?
Device Drivers and SLAM
Device Driver
API Rules
(SLIC)
IO Manager Interface
State MachineFor Locking
Unlocked Locked Error
U
L
L
U
state {
int locked = 0;
}
Lock.call {
if (locked==1) abort;
else locked = 1;
}
UnLock.call {
if (locked==0) abort;
else locked = 0;
}
Demo
State MachineFor Irp Handling
init
pending
Error
IoMarkIrpPending
return:status != STATUS_PENDING
complete
IoCompleteRequest
return: status == STATUS_PENDING
IRP Complete/Pending Rulestate {
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
Boolean program
c2bp
bebop
Fail, p
Pass
newton
GOLF
SLIC
CFG + VFG
predicates
Error GUI
Spec.
predicates
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)
Statement in P:s : nPackets = nPackets+1;
Predicates in E: e : (nPacketsOld==nPackets)
Weakest Precondition:pre(s,e): nPacketsOld==nPackets+1
Strengthened WP:F(pre(s,e)): false
c2bp(P,E)
Statement in P:s : nPackets = nPackets+1;
Predicates in E: e : (nPacketsOld==nPackets)
Weakest Precondition:pre(s,!e): !(nPacketsOld==nPackets+1)
Strengthened WP:F(pre(s,!e)): e
c2bp(P,E)
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
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)
WP and pointers
Statement in P:s : *p = *p + 1
Predicates in E: e : (x==2)
WP:WP(s,e): x==2 ???
Morris’ Axiom ofAssignment
Statement in P:s : *p = *p + 1
Predicates in E: e : (x==2)
WP:WP(s,e): ((p!=&x) and x==2) or ((p==&x) and x==1)
WP and pointers
Statement in P:s : *p = *p + 1
Predicates in E: e : (x==2)
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
each abstract step during model checking
requires O(2n) theorem prover queries
b
post
b
n
k
On-line Abstraction:Set of States = Single Tri-vector
each abstract step during model checkingcb requires O(2n) theorem prover queries
c
c
b
post
b
SLAM - Off-line Abstraction:Set of States = Set of Tri-vectors
each abstract step during model checking
requires O(2n*k) operations, k=O(2n )
c2bpbebop
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
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
Conditions:
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
Conditions:
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
Conditions:
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
Conditions:
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
Conditions:
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
(5) request: (3,4)
Conditions:
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
(5) request: (3,4)
Conditions:
! (5)
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
(5) request: (3,4)
Conditions:
! (5)
!= (1,2)
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
(5) request: (3,4)
Conditions:
!= (1,2)
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
Conditions:
!= (1,2)
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Predicates:
(nPacketsOld == )
(nPackets == )
( != )
Example
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Predicates:
(nPacketsOld != nPackets)
Example (2)
assume(x > y);
y := y - 1;
assume ( !(x > y));
Store:
Conditions:
Example (2)
assume(x > y);
y := y - 1;
assume ( !(x > y));
Store:
(1) x :
(2) y :
Conditions:
> (1,2)
Example (2)
assume(x > y);
y := y - 1;
assume ( !(x > y));
Store:
(1) x :
(3) y : - 1 (2)
Conditions:
> (1,2)
History:
(2) y :
Example (2)
assume(x > y);
y := y - 1;
assume ( !(x > y));
Store:
(1) x :
(3) y : - 1 (2)
Conditions:
> (1,2)
!( > -1 ) (1,3)
History:
(2) y :
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]
Related Work Model checkers
Temporal logic model checking [Clarke-Emerson][Sifakis][Vardi-Wolper]
Symbolic model checking BDDs [Bryant] SMV [McMillan, Clarke]
Model checking of Hiearchical FSMs [Alur,Grosu], [Alur, Yannakakis, et al.], [Benedikt,Godefroid,Reps]
Abstract Interpretation [Cousot-Cousot]
Program Analysis shape analysis [Sagiv-Reps-Wilhelm]
Predicate Abstraction [Graf-Saidi][Das-Dill-Park]
Dataflow analysis=Model Checking + Abstract Interpretation
[Steffen-Schmidt] Counterexample driven refinement
[Kurshan, Clarke-Grumberg-Jha-Lu-Veith] Temporal safety property checking as type checking
[DeLine-Fahndrich] ESP
[Das]
Future Directions New Models
boolean programs lack expressivity
The Heap pointer logics recursive types
Concurrency predicate abstraction for an Owicki/Gries-style logic?
Scaling reinvestigate assume/guarantee for software
SLAM Papers The SLAM Process
Automatically Validating Temporal Safety Properties of Interfaces Thomas Ball, Sriram K. Rajamani, SPIN 2001
The SLAM Toolkit, Thomas Ball, Sriram K. Rajamani, CAV 2001 Boolean Programs: A Model and Process for Software Analysis, Thomas
Ball, Sriram K. Rajamani, MSR Technical Report 2000-14
Boolean Programs Bebop: A Path-sensitive Interprocedural Dataflow Engine, Thomas Ball,
Sriram K. Rajamani, PASTE 2001 Bebop: A Symbolic Model Checker for Boolean Programs, Thomas Ball,
Sriram K. Rajamani, SPIN 2000.
Predicate Abstraction of C Programs Automatic Predicate Abstraction of C Programs, Thomas Ball, Rupak
Majumdar, Todd Millstein, Sriram K. Rajamani, PLDI 2001 Polymorphic Predicate Abstraction, Thomas Ball, Todd Millstein, Sriram K.
Rajamani, MSR Technical Report 2001-10 Boolean and Cartesian Abstractions for Model Checking C Programs,
Thomas Ball, Andreas Podelski, Sriram K. Rajamani, TACAS 2001
Concurrency Parameterized Verification of Multithreaded Software Libraries, Thomas
Ball, Sagar Chaki, Sriram K. Rajamani, TACAS 2001
Thanks to…
Sagar Chaki (CMU) Rupak Majumdar (UC Berkeley) Todd Millstein (U Washington) Andreas Podelski (MPI) Members of Software Productivity
Tools group and PPRC
Summary
Fully automated way to check temporal safety properties of software interfaces
Tools are based on novel ideas interprocedural dataflow with BDDs (bebop) predicate abstraction of C (c2bp) predicate discovery (newton)
Demonstration on Windows 2000 device drivers
Software Productivity ToolsMicrosoft Research
http://research.microsoft.com/slam/
http://msrweb/slam/