Software Verification via Refinement Checking Sagar Chaki, Edmund Clarke, Alex Groce, CMU Somesh...
-
date post
18-Dec-2015 -
Category
Documents
-
view
220 -
download
0
Transcript of Software Verification via Refinement Checking Sagar Chaki, Edmund Clarke, Alex Groce, CMU Somesh...
Software Verification via Refinement Checking
Sagar Chaki, Edmund Clarke, Alex Groce, CMU
Somesh Jha, Wisconsin
Motivation• Refinement mappings exist between real
code and specifications
• Potentially cheaper than model checking- Simulation vs. Trace containment
• Refinement mappings are like proofs
Specifications• Expressed as Finite Labeled Transition
Systems (FLTS)- Locking protocols
• We use the FSP syntax to describe FLTSs- Concurrency: State Models and Java Programs –
Jeff Magee, Jeff Kramer - Wiley
Specification: LockUnlock• U = (lock -> L | return -> S),
L = (unlock -> U).
U L
lock
unlock
S
return
Implementation: Device drivervoid example() {
do {
KeAcquireSpinLock(); //event lock
nPackets = nPacketsOld;
if(cond) {
KeReleaseSpinLock(); //event unlock
nPackets++;
}
} while(nPackets != nPacketsOld);
KeReleaseSpinLock(); //event unlock
}
Our Goal• To show that Driver refines LockUnlock
- Need to keep track of the predicate (nPackets == nPacketsOld)
- Data-insensitive analysis will fail
• Provide diagnostic feedback in case the simulation does not exist
Specification: POSIX pthread• pthread_mutex_lock()
- Acquires lock and returns 0- Increments user count on lock and returns 0- Returns non-zero error code
S0
S1
S3
S2
ret_err
ret_zerolock
inc_count
Implementation: Glibc pthreadint pthread_mutex_lock() {
case PTHREAD_MUTEX_RECURSIVE_NP:
self = thread_self();
if (mutex->__m_owner == self) {
mutex->__m_count++; // inc_count
return 0; // ret_zero
}
pthread_lock(&mutex->__m_lock, self); // lock
mutex->__m_owner = self;
mutex->__m_count = 0;
return 0; } // ret_zero
Implementation• Collection of C procedure definitions
- The pthread library
• Designated main procedure- The pthread_mutex_lock function- We are interested in behavior observed during an
invocation of main
Implementation• For each procedure called, one of two things
must be available
- Definition of procedure
- Information about behavior observed during invocation of procedure
Verification• Check that every possible behavior of main is
also a behavior of the FLTS- Trace-containment
• In practice it is sufficient to check for a stronger condition viz. simulation- FLTS ≥ main
FLTS: Definition• Fix an alphabet: Σ
- Assume Σ contains special symbol ε
• Three-tuple: <Q,I,δ>- Q: finite set of states- I: initial state- δ: transition relation over Q X Σ X Q
Example
U’ L’
lock
S’
return
V’ε
M’ε
unlock
Simulation• FLTSs: <Q1,I1,δ1>,<Q2,I2,δ2>• Relation ≥ Q1 X Q2 is simulation if
(1) Init: For all t Є I2 exists s Є I1 s.t. s ≥ t
(2) Step: s ≥ t and (t,a,t’) Є δ2 => exists s’ s.t. (s,a,s’) Є δ1 and s’ ≥ t’
(3) Stutter: s ≥ t and (t,ε,t’) Є δ2 => s ≥ t’ OR exists s’ s.t. (s,ε,s’) Є δ1 and s’ ≥ t’
Overall method• Step 1: Compute relation R that satisfies
conditions 2 and 3
• Step 2: Check that R satisfies condition 1 as well
Step 1• Start with R = Q1 X Q2
• Iteratively refine R using condition 2 and 3 till a fixed point is reached- If (s,t) Є R and if (t,a,t’) Є δ2 then remove (s,t) if
there does not exist s’ s.t. (s,a,s’) Є δ1 and (s’,t’) Є R
Example
U’ L’
lock
S’
return
V’ε
M’ε
unlock
{U,L,S}
{U,L,S}
{U,L,S}
{U,L,S}
{U,L,S}
lockU L
unlock
Sreturn
Example
U’ L’
lock
S’
return
V’ε
M’ε
unlock
{U}
{U,L,S}
{U,L,S}
{U,L,S}
{U,L,S}
lockU L
unlock
Sreturn
Example
U’ L’
lock
S’
return
V’ε
M’ε
unlock
{U}
{U}
{U,L,S}
{U,L,S}
{U,L,S}
lockU L
unlock
Sreturn
Example
U’ L’
lock
S’
return
V’ε
M’ε
unlock
{U}
{U}
{U,L,S}
{L}
{U,L,S}
lockU L
unlock
Sreturn
Example
U’ L’
lock
S’
return
V’ε
M’ε
unlock
{U}
{U}
{L}
{L}
{U,L,S}
lockU L
unlock
Sreturn
FLTS from C module• Based on a set of predicates
• Each state of the FLTS consists of a control location of the C module and a valuation to the predicates- Non-context-sensitive
• Weakest preconditions and theorem proving are used to compute the transitions on-the-fly
Examplevoid example() {
do {
KeAcquireSpinLock();
nPackets = nPacketsOld;
if(cond) {
KeReleaseSpinLock();
nPackets++;
}
} while(nPackets != nPacketsOld);
KeReleaseSpinLock();
}
Θ: nPackets == nPacketsOld
Θ’
Θ’
Θ’
Θ’
Θ’
Θ’
Θ’
Θ’
Θ’
Θ’
Θ’
Θ
Θ
Θ
Θ
Θ
Θ
Θ
Θ
Θ
Θ
Θ
Loc Loc
Unl Unl
Unl Unl
Ret Ret
Challenges• Extract event information from C code• Provide diagnostic feedback in case
simulation is not found• Pointers and dynamic memory allocation• Introduce context-sensitivity• Introduce concurrency
Predicates and Property• Need to specify predicates to be used
- predicate (nPackets == nPacketsOld);
• Need to specify the simulation relation to be checked- property U simulates example;
Additional Info• Specify that call to KeAcquireSpinLock()
represents a locking action- action call KeAcquireSpinLock = lock;
• Similarly for KeReleaseSpinLock()- action call KeReleaseSpinLock = unlock;
Using Static Analysis• Mostly for alias information
- Predicate : (x == 4)- Assignment : *y = 5;- WP: ((y == &x)&&(5 == 4)) || ((y != &x)&&(x==4))- Static analysis could tell us whether (y == &x)
before this assignment statement
- x = (*y)(100);- What procedures could y potentially point to
Java• Java source
- Object-oriented-ness
• Java bytecode- Stack based- Need to finitise the state, perhaps by imposing a
upper bound on the stack size
Refinements as Proofs• Class loader obtains bytecode with the spec,
refinement relation and set of predicates
• Checks that the refinement really is valid using the predicates
• Loads class only if the check passes
Refinements as Proofs• Tradeoff between bandwidth and computation
- Supply just the predicates and let the loader compute the refinement relation
- Supply the refinement so that loader just has to check its validity
• Can we do this for the Linux process loader- Doubtful
Related Work• Based on predicate abstraction
- Graf & Saidi, Dill et. al.• Do not work with C
- SLAM, Bandera
• Specify desired behavior as patterns, or unwanted behavior as monitors- Engler et. al., SLAM, Bandera
Major Differences• Unlike Engler et. al.
- Flow-sensitive, based on predicates- Check arbitrary regular behavior
• Unlike SLAM- On-the-fly: no boolean programs- Not context-sensitive
• Unlike Bandera- Work with C- Check arbitrary regular behavior