Tevfik Bultan
Department of Computer Science
University of California, Santa Barbara
• Aysu Betin-Can
– Design for verification
• Tuba Yavuz-Kahveci, University of Florida, Gainesville
• Constantinos Bartzis, Carnegie Mellon University
– Action Language Verifier
– Infinite state model checking
• Xiang Fu, Georgia Southwestern State University
– Verification, realizability and synchronizability of web service conversations
• Scalability of software model checking depends on
– Extracting compact models from programs
• This typically requires a reverse engineering step based on user guidance and/or static analysis techniques to
– Rediscover some information about the software that may be known at design time
• Alternative approach: Design for verification
– Structure software in ways that facilitate verification
– Document the design decisions that can be useful for verification
– Improve the scalability of verification using this information
We have been investigating a design for verification approach based on the following principles:
1. Using design patterns that facilitate automated verification
2. Use of stateful, behavioral interfaces which isolate the behavior and enable modular verification
3. An assume-guarantee style verification strategy which separates verification of the behavior from the verification of the conformance to the interface specifications
4. A general model checking technique for interface verification
5. Domain specific and specialized verification techniques for behavior verification
• Design for verification for concurrent programs
– Checking correctness of synchronization
– Behavior verification using Action Language Verifier
– Interface verification using Java Path Finder and thread isolation
• Design for verification for web services
– Checking correctness of conversations
– Behavior verification using Spin and synchronizability analysis
– Interface verification using Java Path Finder and thread isolation
• Java uses a variant of monitor programming
• Synchronization using locks
– Each object has a lock synchronized(o) { ... }
• Coordination using condition variables
– Objects can be used as condition variables synchronized (condVar){ while (!
condExp ) wait( condVar );
... notifyAll( condVar );
}
• Nested locks synchronized m(other) { other.m(); } run() { o1.m(o2); } run() { o2.m(o1); }
• Missed notification notify( condVar );
• Forgotten condition check if(!
condExp ) wait( condVar );
• Dependencies of condition variables can be complicated
– Conservative notification and condition check
• Inefficient
– Optimizing the notification and condition checks
• Error prone
• A verifiable behavioral design pattern for concurrent programs
– Defines customized synchronization policies
– Avoids usage of error-prone Java synchronization primitives: synchronize , wait , notify
– Separates controller behavior from the threads that use the controller
• Supports a modular verification approach which exploits this modularity for scalable verification
}
SharedStub
+a()
+b()
Shared
+a()
+b() a(){
SharedInterface assert(contr.state)==…;
ThreadA
ControllerInterface
ThreadB
Controller
-var1
-var2
+Controller
+action1()
+action2()
ControllerStateMachine
+action1()
+action2()
} transition(){… assert(th.state)==s;
StateTable
+transition()
Action
+blocking()
+nonblocking()
-GuardedExecute int GuardedCommand
GuardedCommand
+guard()
+update()
class RWController implements
RWInterface{ int nR; boolean busy; final Action act_r_enter, act_r_exit; final Action act_w_enter, act_w_exit;
RWController() {
...
gcs = new Vector(); gcs.add(new GuardedCommand() { public boolean guard(){
} return ( nR == 0 && !busy
);} public void update(){ busy = true ;}}
); act_w_enter = new Action(this,gcs); public void w_enter(){ act_w_enter.blocking();} public boolean w_exit(){ return act_w_exit.nonblocking();} public void r_enter(){ act_r_enter.blocking();} public boolean r_exit(){ return act_r_exit.nonblocking();}
}
This helper class is provided, no need to rewrite it class Action{ protected final Object owner; … private boolean GuardedExecute(){ boolean result=false; for(int i=0; i<gcV.size(); i++) try{ if(((GuardedCommand)gcV.get(i)).guard()){
((GuardedCommand)gcV.get(i)).update(); result=true; break; }
}catch(Exception e){} return result;
} public void blocking(){ synchronized(owner) { while(!GuardedExecute()) {
} try{owner.wait();} catch (Exception e){} }
} owner.notifyAll(); } public boolean nonblocking(){
} synchronized(owner) { boolean result=GuardedExecute(); if (result) owner.notifyAll(); return result; }
• A controller interface defines the acceptable call sequences for the threads that use the controller
• Interfaces are specified using finite state machines idle r_enter r_exit w_exit w_enter reading writing public class RWStateMachine implements
RWInterface{
StateTable stateTable; final static int idle=0,reading=1, writing=2; public RWStateMachine(){ ... stateTable.insert("w_enter",idle,writing);
}
} public void w_enter(){ stateTable.transition("w_enter");
}
...
• Possible inefficiencies:
– After every action execution in the controller all the waiting threads are awakened
– The inner classes and the large number of method invocations may degrade the performance
• Solution: Generate an optimized controller automatically using specific notification pattern
• Optimized controller
– Uses the specific notification pattern
– Does not have any inner classes
– Reduces the number of method invocations
public class ReadersWriters{ private int nr; private boolean busy; private Object r_enterCond, w_enterCond; private synchronized boolean Guard_r_enter() { if ( !busy
) { nr++ ; return true;
All condition variables and
} else return false; wait and signal operations are
} public void r_enter() { synchronized(r_enterCond) { while(!Guard_r_enter()) r_enterCond.wait(); generated automatically
} public void r_exit() { synchronized(this) { nr--; } synchronized(w_enterCond) { w_enterCond.notify(); }
}
...
}
Java Controller Class and
Controller Interface based on the
Concurrency
Controller Pattern
Data Stubs
Concurrent
Program
Behavior Translator
Notification-Optimizer
Thread Isolation
Behavior
Specification in Action
Language
Behavior Verification
Action Language
Verifier
Optimized
Java Code
Error Trace Verified
Interface Verification
Java PathFinder
Program with
Stubs
Error Trace Verified
Behavior verification
• Verify the controller properties (e.g. safety, liveness) assuming that the user threads adhere to the controller interface
• Use a customized model checker
Interface verification
• Check that each user thread obeys the interface
– A thread is correct with respect to an interface if all the call sequences generated by the thread can also be generated by the interface machine
• Use a software model checker with stubs
– Significant state space reduction because of stub substitution
• Verification tool: Action Language Verifier
• Advantages: Action Language Verifier can verify controllers
– with parameterized constants and unbounded variables
– for arbitrary number of user threads
Behavior Verification Steps:
• Automatically generate Action Language specifications from the controller class
– based on the actions and the interface of the controller
• Verify properties of concurrency controllers using Action
Language Verifier
– Properties can be specified (by the user) at the code level or Action Language level
• A state based language
– Actions correspond to state changes
• States correspond to valuations of variables
– boolean
– enumerated
– integer (possibly unbounded)
– heap variables (i.e., pointers)
• Parameterized constants
– specifications are verified for every possible value of the constant
• Transition relation is defined using actions
– Atomic actions: Predicates on current and next state variables
– Action composition:
• asynchronous (|) or synchronous (&)
• Modular
– Modules can have submodules
– A module is defined as asynchronous and/or synchronous compositions of its actions and submodules
module main() integer nr; boolean busy; restrict: nr>=0; initial: nr=0 and !busy; module ReaderWriter() enumerated state {idle, reading, writing}; initial: state=s0; r_enter: state=idle and !busy and nr’=nr+1 and state’=reading; r_exit: state=reading and nr’=nr-1 and state’=idle; w_enter: state=idle and !busy and nr=0 busy’ and state’=writing; w_exit: state=writing and !busy’ and state’=idle;
ReaderWriter: r_enter | r_exit | w_enter | w_exit; endmodule main: ReaderWriter() | ReaderWriter() | ReaderWriter(); spec: invariant(busy => nr=0) spec: invariant(busy => eventually(!busy)) endmodule
Action Language
Specification
Action Language
Parser
Composite Symbolic Library
Model Checker
Counter-example
Not sure
Verified
Omega
Library
Presburger
Arithmetic
Manipulator
CUDD
Package
BDD
Manipulator
MONA
Automata
Manipulator
Symbolic
+intersect()
+union()
+complement()
+isSatisfiable()
+isSubset()
+pre()
+post()
BoolSym
–representation: BDD
+intersect()
+union()
•
•
•
CUDD Library
IntSym
–representation: Polyhedra
+intersect()
+union()
•
•
•
CompSym
–representation: list of comAtom
+intersect()
+ union()
•
•
•
OMEGA Library compAtom
–atom: *Symbolic
Symbolic
+union()
+isSatisfiable()
+isSubset()
+forwardImage()
IntBoolAutoSym
–representation: automaton
+union()
•
•
•
InAutotSym
–representation: automaton
+union()
•
•
•
BoolSym
–representation:
BDD
+union()
•
•
•
HeapSym
–representation: list of ShapeGraph
+union()
•
•
•
IntPolySym
–representation: list of Polyhedra
+union()
•
•
•
CompSym
–representation: list of comAtom
+ union()
•
•
•
MONA CUDD shapeGraph
–atom: *Symbolic
OMEGA compAtom
–atom: *Symbolic
• Counting abstraction
– Create an integer variable for each interface state
– Each variable counts the number of threads in a particular interface state
– Automatically generate updates and guards for these variables based on the interface specification
• Counting abstraction is automated
module main() integer nr; boolean busy; parameterized integer numReaderWriter; restrict: nr>=0 and numReaderWriter>=1; initial: nr=0 and !busy; module ReaderWriter() integer idle, reading, writing ; initial: idle=numReaderWriter; r_enter: idle>0 and !busy and nr’=nr+1 and idle’=idle-1 and reading’=reading+1 ; r_exit: reading>0 and nr’=nr-1 and reading’=reading-1 and idle’=idle+1; w_enter: idle>0 and !busy and nr=0 and busy’ and idle’=idle-1 and writing’=writing+1; w_exit: writing>0 and !busy’ and writing’=writing-1 and idle’=idle+1
ReaderWriter: r_enter | r_exit | w_enter | w_exit; endmodule main: ReaderWriter() * ; spec: invariant(busy => nr=0) spec: invariant(busy => eventually(!busy)) endmodule
RW-4
RW-8
RW-16 1
1
1
Integers Booleans Cons. Time
(secs.)
5
9
17
0.04
0.08
0.19
RW-32 1 33 0.53
RW-64 1
RW-P 7
65
1
1.71
0.05
Ver. Time
(secs.)
0.01
0.01
0.02
0.03
0.06
0.01
Memory
(Mbytes)
6.6
7
8
10.8
20.6
9.1
SUN ULTRA 10 (768 Mbyte main memory)
A simplified model of Seattle Tacoma International Airport from [Zhong 97]
• An airplane can land using 16R only if no airplane is using
16R at the moment
• An airplane can takeoff using 16L only if no airplane is using 16L at the moment
• An airplane taxiing on one of the exits C3-C8 can cross runway 16L only if no airplane is taking off at the moment
• An airplane can start using 16L for taking off only if none of the crossing exits C3-C8 is occupied at the moment
(arriving airplanes have higher priority)
• Only one airplane can use a taxiway at a time
park2 crossRW3 park7 crossRW4 park9 crossRW5 crossRW6 park10 crossRW7 park11 crossRW8 exitRW3 exitRW4 exitRW5 exitRW6 exitRW7 exitRW8 reqLand reqTakeOff leave
Airport Ground Traffic Control
• Action Language specification of the controller
– Has 13 integer variables
– Has 6 Boolean variables per airplane process to keep the local state of each airplane
– 20 actions
• Optimized Java concurrency controller class
– Has 13 integer variables
– Has 14 condition variables
– Has 34 methods
A: Arriving Airplane
D: Departing Airplane
P: Arbitrary number of threads
Processes Construction(sec) Verify-P1(sec) Verify-P2(sec) Verify-P3(sec)
2
4
8
16
2A,PD
4A,PD
8A,PD
16A,PD
PA,2D
PA,4D
PA,8D
PA,16D
PA,PD
1.94
3.95
8.74
1.67
3.15
0.81
1.50
3.03
6.86
1.02
6.40
13.66
2.65
1.19
2.28
4.6
1.31
2.42
0.42
0.78
1.53
3.02
0.64
4.64
9.21
0.99
0.81
1.54
3.15
0.88
1.71
0.28
0.50
0.99
2.03
0.43
3.32
7.02
0.57
1.39
2.59
5.35
3.94
5.09
0.69
1.13
2.22
5.07
0.83
7.35
12.01
0.43
• Verification tool: Java PathFinder (JPF)
• Advantages: JPF Can check arbitrary thread implementations
Interface Verification Steps:
• Isolate each thread implementation using stubs generated from the controller interfaces
• Check each thread implementation separetly for interface violations using JPF
• Replace the instances of the controllers with the corresponding stubs
– i.e., the interface state machines
• Replace the shared data protected by these controllers with data stubs
– Interface verification will check if a user thread accesses shared data only when it is in a correct interface state
• Significant reduction in state space
• Thread isolation assumption
– Threads only interact through the controllers and the shared data that are protected by these controllers
• Close the environment of a thread
– User input (user interfaces)
– RMI interaction
– Network communication
– File I/O
• Check each thread implementation separately
• 2800 lines of Java code with
– 17 class files
– 5 controller classes
– 7 Java interfaces
• Implemented using concurrency controller pattern without writing any Java synchronization operations
Server
Mediator
ServerDocument
<<RMI>>
Client
GUI
LocalDocument
• Handling RMI methods: isolation
– Drivers: simulating incoming calls to a node
– Stubs: simulating outgoing calls to another node
• Handling GUI interactions
– Driver: simulates the user interactions
• Threads in the Server
– Threads serving RMI requests
• Threads in a Client other than main
– Event Thread capturing GUI events
– Worker Thread per paragraph
• Event thread creates Worker threads
– Less abstraction in data stubs of the Event thread
Behavior Verification with ALV
Controllers T (sec) M (MB)
Mutex 0.01
6.00
2.05
6.47
Bounded
Buffer
Barrier
Reader
Writer
0.01
0.42
0.5
6.94
Interface Verification with JPF
Threads T (sec) M (MB)
Server
RMI
185.85
67.14
Client
RMI
229.18
127.04
Event 1636.62 139.48
Worker 19.47
5.36
• Errors discovered (interface violation errors)
– Caused by not calling the correct controller method before accessing the shared data
– Violation of the controller call sequence because of the incorrectly handled exception blocks
• We applied the same approach to a larger system (TSAFE) and used fault injection to test the effectiveness of our approach
– We can find all the controller errors (depending on the controller properties)
– We can find all interface errors (other than the convoluted ones)
• Challenges
– Thread isolation
• Environment generation
– Scalability of interface verification
– Completeness of controller properties
• Design for verification for concurrent programs
– Checking correctness of synchronization
– Behavior verification using Action Language Verifier
– Interface verification using Java Path Finder
• Design for verification for web services
– Checking correctness of conversations
– Behavior verification using Spin and synchronizability analysis
– Interface verification using Java Path Finder
• Loosely coupled, interaction through standardized interfaces
• Standardized data transmission via XML
• Asynchronous messaging
• Platform independent (.NET, J2EE)
Interaction
Composition
Service
Message
Type
Data
WSCDL
BPEL4WS
WSDL
SOAP
XML Schema
XML
Web Service Standards
Three peers: Investor (Inv) , Stock Broker (SB) , and Research
Department (RD)
• Inv initiates the stock analysis service by sending a register message to the SB
• The SB may accept or reject the registration
• If the registration is accepted, the SB sends an analysis request to the RD
• RD sends the results of the analysis directly to the Inv as a report
• After receiving a report the Inv can either send an ack to the SB or cancel the service
• Then, the SB either sends the bill for the services to the
Inv , or continues the service with another analysis request
• SAS is a composite web service
– a finite set of peers : Inv, SB, RD
– and a finite set of message classes : register , ack , cancel , accept , reject , bill , request , terminate , report
Investor
(Inv) report register ack, cancel
Stock Broker
(SB) accept, reject, bill request, terminate
Research Dept.
(RD)
• We assume that the messages among the peers are exchanged using reliable and asynchronous messaging
– FIFO and unbounded message queues
Stock Broker
(SB) req req
Research Dept.
(RD)
• This model is similar to industry efforts such as
– JMS (Java Message Service)
– MSMQ (Microsoft Message Queuing Service)
Investor
!register
?reject
?accept
!ack
?report
?bill
!cancel
?bill
Stock Broker Firm
?register
!reject
!accept
!request
?ack
!bill
?cancel
!bill
!terminate
Research Dept.
?request
!report
?terminate
• Assume that a virtual watcher records the messages as they are sent
Investor
(Inv) register accept
Stock Broker
(SB) ack bill
Watcher reg acc req rep ack bil ter
Research Dept.
(RD)
• A conversation is a sequence of messages the watcher sees during an execution
• We know that analyzing conversations of composite web services is difficult due to asynchronous communication
– Model checking for conversation properties is undecidable even for finite state peers
• The question is:
– Can we identify the composite web services where asynchronous communication does not create a problem?
• A composite web service is synchronizable , if its conversation set does not change
– when asynchronous communication is replaced with synchronous communication
• If a composite web service is synchronizable we can check its properties about its conversations using synchronous communication semantics
– For finite state peers this is a finite state model checking problem
• Sufficient conditions for realizability (no message content)
– Synchronous compatible
• When the peers are composed synchronously, there should not be a state where a peer is ready to send a message while the corresponding receiver is not ready to receive
– Autonomous
• At any state, each peer should be able to do only one of the following: send , receive or terminate
(a peer can still choose among multiple messages)
Problem Set Size
Source Name #msg #states #trans.
ISSTA’04 SAS 9 12 15
CvSetup 4 4 4
IBM
Conv.
Support
MetaConv 4
Chat 2
Buy 5
4
4
5
6
5
6
Project
BPEL spec
Haggle
AMAB shipping
Loan
2
6
8
8
5
10
3
6
8
15
3
6
Collaxa.
com
Auction 9
StarLoan 6
Cauction 5
9
7
7
10
7
6
Synchronizable?
yes yes no yes yes no yes yes yes yes yes yes
Java Controller Class and
Controller Interface based on the
Peer Controller Pattern
Behavior Translator
Synchronizability
Analysis
Distributed
Program
Thread Isolation
Behavior
Specification
In Promela
Behavior Verification
Spin
Error Trace Verified
Program with
Stubs
Interface Verification
Java PathFinder
Error Trace Verified
• Eases the development of web services
• Uses Java API for XML messaging (JAXM)
– Asynchronous communication among peers
• Supported by a modular verification technique
– Behavior Verification: Checks properties of conversations of a web service composed of multiple peers
• assuming that peers behave according to their interfaces
– Interface Verification: Checks if each peer behaves according to its interface
ApplicationThread
PeerServlet
Communicator
CommunicationController
ThreadContainer
CommunicationInterface
StateMachine
• Behavior Verification
– Uses synchronizability analysis
– Uses Spin model checker
• Spin model checker supports asynchronous communication
– Automated translation to Promela
– Verifies properties of conversations
• Interface Verification
– Isolated check of individual peer implementations
– Uses program checker JPF
• Spin is a finite state model checker
– We have to bound the channel sizes, session numbers, message types
• Synchronizability analysis
– Enables us to verify web services efficiently by replacing communication channels with channels of size 0 (i.e., synchronous communication)
– The verification results hold for unbounded channels
• If the call sequence to the Communicator class is accepted by the automata specifying the interface, then the peer implementation conforms to the behavior in the contract
• Interface Verification:
– CommunicationController is replaced with
CommunicatorInterface
– Drivers simulating other peers are automatically generated
• State Space reduction
– Usage of stubs
– Each session is independent
• just need to check each peer for one session
• We used this approach to implement several simple web services
– Travel agency
– Loan approver
– Product ordering
• Performance of both interface and behavior verification were reasonable
Interface Verification with JPF for Loan Approver
Threads T (sec) M (MB)
Customer 8.86
3.84
4.7
Loan
Approver
Risk
Assesor
9.65
8.15
3.64
• Sample Property: Whenever a request with a small amount is sent, eventually an approval message accepting the loan request will be sent.
• Loan Approval system has 154 reachable states
– because each queue length never exceeds 1.
• Behavior verification used <1 sec and 1.49 MB
• SPIN requires restricted domains
– Have to bound the channel sizes bounded message queues
– Problem: No guarantee these results will hold for other queue sizes
!item1Order
!item2Order
!payReq
?receipt
!payment
?bill
?item1Order
?item2Order
?payReq
!receipt
?payment
!bill
• SPIN runs out of memory for message queue size 15!
– Absence of error for queue size 15 does not ensure correctness
– Reachable state space is infinite
• Issue is not only unbounded queues, but also efficiency
• Solution: We use synchronizability analysis
– The example above and Loan Approver are both synchronizable
• We were able to use our design for verification approach based on design patterns and behavioral interfaces in different domains
• Use of domain specific behavior verification techniques has been very effective
• Interface verification is challenging
• Model checking research resulted in various verification techniques and tools which can be customized for specific classes of software systems
• Automated verification techniques can scale to realistic software systems using design for verification approach
• Design for Verification
[Betin-Can, Bultan SoftMC03, ASE04, WWW05, ICWS05]
• Action Language Verifier
[Bultan ICSE 00], [Bultan, Yavuz-Kahveci ASE 01], [Yavuz-Kahveci, Bar,
Bultan CAV 2005]
• Composite Symbolic Library
[Yavuz-Kahveci, Tuncer, Bultan TACAS01], [Yavuz-Kahveci, Bultan FroCos 02,
STTT 03]
• Realizability and Synchronizability of Web Services
[Bultan, Fu, Hull, Su WWW03], [Fu, Bultan, Su CIAA03, TCS04, WWW04,
ICWS04]
• Infinite State Model Checking
[Bar Bultan CIAA02, IJFCS03, CAV03,CAV04]
• Design for Verification
– [Magee, Kramer 99]
• uses LTSA model checker for verification of finite state models of
Java concurrent programs
– [Sharygina, Browne, Kurshan FASE 01]
• presents design rules for object-oriented design models to facilitate verification
– [Mehlitz, Penix Workshop on Component-Based Soft. Eng. 03]
• promotes using design patterns and exploiting their properties in verification
• Design patterns for concurrency
– [Schmidt, Stal, Rohmert, Buschmann 00], [Lea 99], [Grand 02]
• Environment extraction/generation
– [Godefroid, Colby, Jagadeesan PLDI 98], [Tkachuk, Dwyer ASE 03],
[Tkachuk, Dwyer, Pasareanu ESEC/FSE 03]
• Verisoft from Bell Labs [Godefroid POPL 97]
– C programs, handles concurrency, bounded search, bounded recursion, stateless search
• Java Path Finder (JPF) at NASA Ames [Havelund, Visser]
– Explicit state model checking for Java programs, bounded search, bounded recursion, handles concurrency
• SLAM project at Microsoft Research
[Ball, Rajamani et al. SPIN 00, PLDI 01]
– Symbolic model checking for C programs, unbounded recursion, no concurrency
– Uses predicate abstraction [Saidi, Graf 97] and BDDs
• BANDERA: A tool for extracting finite state models from programs
[Dwyer, Hatcliff et al ICSE 00, 01]
• Modular model checking of software components
– [Chaki, Clarke, Groce, Jha, Veith ICSE 03]
• Conversation specification
– IBM Conversation support project http://www.research.ibm.com/convsupport/
– Conversation support for business process integration [Hanson,
Nandi, Kumaran EDOCC’02]
– Orchestrating computations on the world-wide web [Choi, Garg, Rai,
Misram, Vin EuroPar’02]
• Realizability problem
– Realizability of Message Sequence Charts (MSC) [Alur, Etassami,
Yannakakis ICSE’00, ICALP’01]
• Verification of web services
– Simulation, verification, composition of web services using a Petri net model [Narayanan, McIlraith WWW’02]
– BPEL verification using a process algebra model and Concurrency
Workbench [Koshkina, van Breugel TAVWEB’03]
– Using MSC to model BPEL web services which are translated to labeled transition systems and verified using model checking
[Foster, Uchitel, Magee, Kramer ASE’03]
– Model checking Web Service Flow Language specifications using
Spin [Nakajima ICWE’04]
• Conformance checking for asynchronously communicating processes
– [Rajamani, Rehof CAV’02]
• conformance checking between specification model and a model extracted from the implementation