940 likes | 954 Views
Tools for Automated Verification of Concurrent Software. Tevfik Bultan Department of Computer Science University of California, Santa Barbara bultan@cs.ucsb.edu http://www.cs.ucsb.edu/~bultan/ http://www.cs.ucsb.edu/~bultan/composite/. Summary. Goal: Building reliable concurrent software
E N D
Tools for Automated Verification of Concurrent Software Tevfik Bultan Department of Computer Science University of California, Santa Barbara bultan@cs.ucsb.edu http://www.cs.ucsb.edu/~bultan/ http://www.cs.ucsb.edu/~bultan/composite/
Summary • Goal: Building reliable concurrent software • Sub-goals: • Developing reliable concurrency controllers in Java • Developing reliable concurrent linked lists • Approach: Model Checking • Specification Language: Action Language • Tools: • Composite Symbolic Library • Action Language Verifier
Students Joint work with my students: • Tuba Yavuz-Kahveci • Constantinos Bartzis
Outline • Difficulties in concurrent programming • Action Language • Composite Symbolic Library • Application to concurrency controllers • Application to concurrent linked lists • Related work • Current and future work
Difficulties in Concurrent Programming • Concurrent programming is difficult and error prone • In sequential programming you only worry about the states of the variables • In concurrent programming you also have to worry about the states of the threads • State space increases exponentially with the number of threads
Concurrent Programming in Java • 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); }
Dangers in Java Concurrency • Nested locks Thread1 Thread2 synchronized m(other) { other.m(); } Thread1: run() { o1.m(o2); } Thread2: run() { o2.m(o1); } o2 o1 lock lock
Dangers in Java Concurrency • Missed notification notify(condVar); • Forgotten condition check if(!condExp) wait(condVar); • Dependency among multiple condition variables can be complicated • Conservative notification and condition check Inefficient • Optimizing the notification and condition checks Error prone
Example: Airport Ground Traffic Control Simulation A simplified model of Seattle Tacoma International Airport from [Zhong 97]
Control Logic • 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
Java Implementation • Simulate behavior of each airplane with a thread • Use a monitor (a Java class) • private variables for number of airplanes on each runway and each taxiway • methods of the monitor enforce the control logic • Each thread calls the methods of the monitor based on the airport layout to move from one point to the next
Example Implementation public synchronized void C8_To_B11A() { while (!((numRW16L == 0) && (numB11A == 0))) wait(); numC8 = numC8 - 1; numB11A = numB11A + 1; notifyAll(); } • This code is not efficient since every thread wakes up every other thread • Using separate condition variables complicates the synchronization • nested locks
Difficulties In Implementing Concurrent Linked Lists • Linked list manipulation is difficult and error prone • State of the heap: unbounded • State space: • Sequential programming • states of the variables • Concurrent programming • states of the variables • states of the threads • Concurrent linked lists • states of the variables • states of the threads • state of the heap
Examples next • singly linked lists • doubly linked lists • stack • queue • single lock • double lock • allows concurrent inserts and deletes n1 n2 next next next prev n1 n2 prev next top n1 n2 next last first n1 n2 next next
Action Language Tool Set Action Language Verifier Action Language Specification Action Language Parser Composite Symbolic Library Code Generator Omega Library CUDD Package MONA Presburger Arithmetic Manipulator BDD Manipulator Automata Manipulator Verified code (Java monitor classes)
Outline • Difficulties in concurrent programming • Action Language • Composite Symbolic Library • Application to concurrency controllers • Application to concurrent linked lists • Related work • Current and future work
Action Language[Bultan, ICSE 00], [Bultan, Yavuz-Kahveci, ASE 01] • 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
Action Language • 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 Reader() boolean reading; initial: !reading; rEnter: !reading and !busy and nr’=nr+1 and reading’; rExit: reading and !reading’ and nr’=nr-1; Reader: rEnter | rExit; endmodule module Writer() ... endmodule main: Reader() | Reader() | Writer() | Writer(); spec: invariant([busy => nr=0]) endmodule Readers Writers Example S :Cartesian product of variable domains defines the set of states I : Predicates defining the initial states R : Atomic actions of the Reader R : Transition relation of Reader defined as asynchronous composition of its atomic actions R : Transition relation of main defined as asynchronous composition of two Reader and two Writer processes
Outline • Difficulties in concurrent programming • Action Language • Composite Symbolic Library • Application to concurrency controllers • Application to concurrent linked lists • Related work • Current and future work
BDDs canonical and efficient representation for Boolean logic formulas can only encode finite sets Linear Arithmetic Constraints can encode infinite sets two representations polyhedral representation automata representation mapping booleans to integers is not an efficient encoding Which Symbolic Representation to Use? x y {(T,T), (T,F), (F,T)} x F a > 0 b = a+1 T y {(1,2), (2,3), (3,4),...} F T F T
Composite Model Checking[Bultan, Gerber, League ISSTA 98, TOSEM 00] • Map each variable type to a symbolic representation • Map boolean and enumerated types to BDD representation • Map integer type to a linear arithmetic constraint representation • Use a disjunctive representation to combine different symbolic representations: composite representation • Each disjunct is a conjunction of formulas represented by different symbolic representations • we call each disjunct a composite atom
Composite Representation composite atom symbolic rep. 1 symbolic rep. 2 symbolic rep. t Example: x: integer, y: boolean x>0 and x´x-1andy´orx<=0 and x´xandy´y arithmetic constraint representation arithmetic constraint representation BDD BDD
Composite Symbolic Library[Yavuz-Kahveci, Tuncer, Bultan TACAS01], [Yavuz-Kahveci, Bultan FroCos 02, STTT 03] • Uses a common interface for each symbolic representation • Easy to extend with new symbolic representations • Enables polymorphic verification • Multiple symbolic representations: • As a BDD library we use Colorado University Decision Diagram Package (CUDD) [Somenzi et al] • As an integer constraint manipulator we use Omega Library [Pugh et al]
Composite Symbolic Library Class Diagram BoolSym CompSym IntSym –representation: BDD –representation: Polyhedra –representation: list of comAtom +intersect() +union() • • • +intersect() +union() • • • +intersect() + union() • • • compAtom –atom: *Symbolic Symbolic +intersect() +union() +complement() +isSatisfiable() +isSubset() +pre() +post() CUDD Library OMEGA Library
Pre and Post-condition Computation Variables: x: integer, y: boolean Transition relation: R:x>0 and x´x-1andy´orx<=0 and x´xandy´y Set of states: s:x=2and!yorx=0and!y Compute post(s,R)
Pre and Post-condition Distribute R:x>0 and x´x-1andy´orx<=0 and x´xandy´y s:x=2and!yorx=0andy post(s,R) =post(x=2 , x>0 and x´x-1) post(!y , y´) x=1 y • post(x=2 , x<=0 and x´x) post (!y , y´y) false!y • post(x=0 , x>0 and x´x-1) post(y , y´) falsey • post (x=0 , x<=0 and x´x) post (y, y´y ) x=0y =x=1andy orx=0andy
Temporal Properties Fixpoints [Emerson and Clarke 80] EF(p)states that can reach p p Pre(p) Pre(Pre(p)) ... Initial states p • • • EF(p) initial states that satisfy EF(p) initial states that violate AG(p) EG(p) states that can avoid reaching pp Pre(p) Pre(Pre(p)) ... Initial states • • • EG(p) initial states that satisfy EG(p) initial states that violate AF(p)
Polymorphic Verifier SymbolicTranSys::check(Node *f) { • • • Symbolics = check(f.left) caseEX: s.pre(transRelation) caseEF: do sold = s s.pre(transRelation) s.union(sold) while not sold.isEqual(s) • • • } Action Language Verifier is polymorphic It becomes a BDD based model checker when there or no integer variables
Fixpoints May Not Converge • Integer variables can increase without a bound • state space is infinite • Model checking is undecidable for systems with unbounded integer variables • We use conservative approximations
Conservative Approximations • Compute a lower ( p ) or an upper ( p+ ) approximation to the truth set of the property ( p ) • Action Language Verifier can give three answers: I p p p I p 1) “The property is satisfied” 3) “I don’t know” sates which violate the property I p p+ p 2) “The property is false and here is a counter-example”
Conservative Approximations • Truncated fixpoint computations • To compute a lower bound for a least-fixpoint computation • Stop after a fixed number of iterations • Widening • To compute an upper bound for the least-fixpoint computation • We use a generalization of the polyhedra widening operator by [Cousot and Halbwachs POPL’77]
Widening • Widening operation with composite representation: • Given two composite atoms c1 and c2 in consecutive fixpoint iterates, assume that c1 = b1 i1 c2 = b2 i2 where b1 = b2 and i1 i2 Assume that i1 is a single polyhedron and i2 is also a single polyhedron We find pairs of composite atoms which satisfy this criteria
Widening • Assuming that i1 and i2 are conjunctions of atomic constraints (i.e., polyhedra), then i1 i2 is defined as: all the constraints in i1 which are also satisfied by i2 Example: i1=0count count2 i2=0count count3 i1 i2 =0count • Replace i2 with i1 i2 in c2 • This generates an upper approximation for the least fixpoint computation This constraint is not satisfied by i2 so we drop it
Composite Symbolic Library with Automata Encoding IntBoolSymAuto IntSymAuto BoolSym IntSym CompSym –representation: BDD –representation: automaton –representation: automaton –representation: list of Polyhedra –representation: list of comAtom +union() • • • +union() • • • +union() • • • +union() • • • + union() • • • compAtom –atom: *Symbolic Symbolic +union() +isSatisfiable() +isSubset() +forwardImage() MONA CUDD Library OMEGA Library
Automata Representation for Arithmetic Constraints[Bartzis, Bultan CIAA’02, IJFCS ’02] • Given an atomic linear arithmetic constraint in one of the following two forms we construct an FA which accepts all the solutions to the given constraint • By combining such automata one can handle full Presburger arithmetic
Basic Construction 0 1 2 • We first construct a basic state machine which • Reads one bit of each variable at each step, starting from the least significant bits • and executes bitwise binary addition and stores the carry in each step in its state 0 1 0 0 / / 0 1 0 1 / 1 1 0 / 0 0 1 1 1 / / 0 1 Example x + 2y 0 1 / 0 1 1 / 1 1 1 / 0 010 + 2 001 0 0 / 1 0 1 0 0 / / 0 1 1 0 0 Number of states:
Automaton Construction • Equality With 0 • All transitions writing 1 go to a sink state • State labeled 0 is the only accepting state • For disequations (), state labeled 0 is the only rejecting state • Inequality (<0) • States with negative carries are accepting • No sink state • Non-zero Constant Term c • Same as before, but now -c is the initial state • If there is no such state, create one (and possibly some intermediate states which can increase the size by |c|)
Conjunction and Disjunction 0 0 1 0,1,1 0 1 0,1 1 0 Automaton for x-y<1 1 0 1 0 -1 0 1 0 1 0 0 1 0,1,1 0 0 0,1 0 0 0,1 0,-1 0 0 1 1 1 0 1 1 1 0,1 0 1 Automaton for x-y<1 2x-y>0 1 0 0 1 0,1 Automaton for 2x-y>0 0 1 0,1 0 1 0,1 -1,-1 -1,0 -1 0 0 1 0 0 0 0 0 1 0 1 0 1 0 0 1 1,1 0 1 1,1 1 0 0 1 1 1,0,1 -2,-1 -2,0 -2,1 -2 0 1 1 0 1 1 • Conjunction and disjunction is handled by generating the product automaton
Other Extensions • Existential quantification (necessary for pre and post) • Project the quantified variables away • The resulting FA is non-deterministic • Determinization may result in exponential blowup of the FA size but we do not observe this in practice • For universal quantification use negation • Constraints on all integers • Use 2’s complement arithmetic • The basic construction is the same • In the worst case the size doubles
Experiments • We implemented these algorithms using MONA [Klarlund et al] • Integrated them to the Action Language Verifier • We verified a large number of specification examples • We compared our representation against • the polyhedral representation used in the Omega library • the automata representation used in LASH • we also integrated LASH to the Composite Symbolic Library using a wrapper around it
Efficient Pre- and Post-condition Computations[Bartzis, Bultan CAV’03] • Pre and post condition computations can cause an exponential blow-up in the size of the automaton in the worst case • We do not observe this blow-up in the experiments • We proved that for a common class of systems this blow up does not occur
Assumptions About the Transition Relation • We assume that the transition relation of the input system is a disjunction of formulas in the following form guard(R) update(R) where • guard(R) is a Presburger formula on current state variables and • update(R) is of the form xi’=f(x1, …, xv) xj’= xj • In asynchronous concurrent systems the transition relation is usually in the above form ji
Three Classes of Updates • xi’ = c • xi’ = xi + c • xi’ = j=1aj· xj + c We proved that • Computation of pre is polynomial for all 3 cases • Computation of post is polynomial for 2 and for 3, whenever ai is odd. v
Other Results Related to Automata Encoding[Bartzis, Bultan TACAS’03, STTT, CAV’04] • We developed efficient algorithms for BDD construction for bounded linear arithmetic constraints • We showed that all three versions of SMV (NuSMV, CMU SMV and Cadence SMV) are inefficient in handling linear arithmetic constraints • We defined a widening operator for the automata representation of arithmetic constraints • We can prove that for some cases this widening operator computes the exact fixpoint (for example for updates of the form x’=x+c)
Outline • Difficulties in concurrent programming • Action Language • Composite Symbolic Library • Application to concurrency controllers • Application to concurrent linked lists • Related work • Current and future work