470 likes | 482 Views
CS 290C: Formal Models for Web Software Lecture 3: Verification of Navigation Models with the Spin Model Checker Instructor: Tevfik Bultan. Verifying navigation models. Web application typically have some navigation constraints that they wish to enforce. For example
E N D
CS 290C: Formal Models for Web Software Lecture 3: Verification of Navigation Models with the Spin Model CheckerInstructor: Tevfik Bultan
Verifying navigation models • Web application typically have some navigation constraints that they wish to enforce. • For example • Transition to a particular page must be via a specific other page. For example, a page displaying the contents of the shopping cart must be displayed before proceeding to the checkout • From any position in the application the users should be able to go back to the home page • We would like to check these types of constraints on the navigation model
Verifying navigation models • Verification of navigation models can be done in two ways • We can first construct the navigation model, verify it, and then while implementing the application we can enforce the navigation model (forward engineering) • If we can enforce the navigation model precisely, then verification results hold for the final application • We can try to extract the navigation model from an existing application by analyzing the application, and then verify the properties of the extracted model (reverse engineering) • If the automatically extracted model is precise, then the verification results hold for the application
What can we do after generating navigation models? • As I said last week, after we obtain a formal model of the navigation behavior we can verify it. • This brings up two questions: • How are we going to characterize properties of navigation models? • For this we will briefly discuss temporal logics • How are we going to verify these properties on the navigation model • For this we will discuss the Spin model checker
Transition Systems • Transition systems are a very basic model used in automated verification • The idea is to model a system with just states and transitions • It is basically a flat state machine • A transition system T = (S, I, R) consists of • a set of states S • a set of initial states I S • and a transition relation R S S • Semantics of many formal languages (including statecharts) can be defined using transition systems
Execution Paths • An execution path is an infinite sequence of states x = s0, s1, s2, ... such that s0 I and for all i 0, (si,si+1) R Notation: For any path x xi denotes the i’th state on the path (i.e., si) xi denotes the i’th suffix of the path (i.e., si, si+1, si+2, ... )
Temporal Logics • Temporal logics are a type of modal logics • Modal logics were developed to express modalities such as “necessity” or “possibility” • Temporal logics focus on the modality of temporal progression • Temporal logics can be used to express, for example, that: • an assertion is an invariant (i.e., it is true all the time) • an assertion eventually becomes true (i.e., it will become true sometime in the future)
Temporal Logics • We will assume that there is a set of basic (atomic) properties called AP • Atomic properties are the basic, non-temporal properties that can be checked by looking at the current state of the system • We will use the usual boolean connectives: , , • We will also use four temporal operators: Invariantp : G p (aka p) (Globally) Eventuallyp : F p (aka p) (Future) Next p : X p (aka p) (neXt) pUntilq : p U q
Atomic Properties • In order to define the semantics we will need a function L which evaluates the truth of atomic properties on states: L : S AP {True, False} So given a state of the transition system and an atomic property, the function L determines if the property holds on that state or not.
Linear Time Temporal Logic (LTL) Semantics Given an execution path x and LTL properties p and q x |= p iff L(x0, p) = True, where p AP x |=p iff not x |= p x |= p q iff x |= p and x |= q x |= p q iff x |= p or x |= q x |= X p iff x1 |= p x |= G p iff for all i 0, xi |= p x |= F p iff there exists an i 0 such that xi |= p x |= p U q iff there exists an i 0 such that xi |= q and for all 0 j < i, xj |= p
LTL Properties . . . X p p . . . G p p p p p p p . . . F p p . . . p U q p p p p q
LTL Equivalences • We do not really need all four temporal operators • X and U are enough (i.e., X, U, AP and boolean connectives form a basis for LTL) F p = true U p G p = (Fp) = (true U p)
LTL Model Checking • Given a transition system T and an LTL property p T |= p iff for all execution paths x in T, x |= p Model checking problem: Given a transition system T and an LTL property p, determine if T is a model for p (i.e., if T |=p)
LTL Properties Transition System T = (S, I, R) T |= X p T |= F p T |= G p T |= F p p p s1 s2 s3 s4 S = {s1, s2, s3, s4} I = {s3} R ={(s1,s2), (s2,s3), (s3,s1),(s3,s4), (s4,s3)} s1 |= p s2 |= p s3 |= p s4 |= p
Example navigation properties in temporal logic • F(main-page): main-page is eventually reached • G(F(exit-page)): always eventually exit-page is reached • G(purchase-page => X(X(payment-page))): payment-page is reached two clicks after the purchase-page
Model Checkers • There are model checking tools that can check temporal logic properties on transition systems • Spin is a well-known LTL model checker • We will discuss it next • Spin can be used to check properties of finite state systems (such as statecharts specifications)
Verifying navigation models One specific approach to verification of navigation models • Write navigation properties in LTL • Write the navigation model in the Promela language (the input language for the Spin model checker) • Use the Spin model checker to check the properties on the Promela specification • Spin model checker outputs error traces for the properties that are violated
SPIN • Explicit state model checker • Finite state • Temporal logic for specifying properties: LTL • Input language: PROMELA • Asynchronous processes • Shared variables • Message passing through (bounded) communication channels • Variables: boolean, char, integer (bounded), arrays (fixed size) • Structured data types A good overview paper for the Spin model checker: ``The Model Checker SPIN,’’ Gerard J. Holzmann, IEEE Trans. Soft. Eng., 23(5) 279-295, 1997.
LTL Model Checking Summary • Each LTL property can be converted to a type of automaton • Generate the property automaton from the negated LTL property • Generate the product of the property automaton and the transition system • Show that there is no accepting (infinite) path in the product automaton (check language emptiness) • i.e., show that the intersection of the paths generated by the transition system and the paths accepted by the (negated) property automaton is empty • If there is an accepting path, it corresponds to a counterexample behavior that demonstrates the bug
LTL properties can be converted to automata These are specific type of automata that accepts infinite strings (they are called Buchi autoamata) true p G p p true p F p p p p p G (F p) p
LTL Model Checking Summary • We can think of the input transition system as also an automaton if we make all the states of the transition system accepting states • Then, if we generate a property automaton from the negated LTL property and take the product of the property automaton and the transition system • If the transition system satisfies the property, this product automaton should not accept any strings • So, we can check if the language accepted by the property automaton is empty or not • If it is empty, then the transition system satisfies the property • If it is not empty, any accepting sequence corresponds to a behavior that violates the original property
SPIN Verification in SPIN • Uses the LTL model checking approach • Constructs the product automaton on-the-fly • It is possible to find an accepting path (i.e. a counter-example) without constructing the whole state space • Uses a nested depth-first search algorithm to look for an accepting path (which is must end in a cycle since we are looking for infinite paths) • Uses various heuristics to improve the efficiency of the nested depth first search: • partial order reduction • state compression
Promela (PROcess MOdeling LAnguage) • Basic data types and ranges • bit (or bool) 0..1 • byte 0..255 • short -215-1 .. 215-1 • int -231-1 .. 231-1 bool flag; /* declares a boolean array */ int state; /* declares an integer variable called state */ • Array variables byte myarray[N] /* decleras an array of size N */
Processes • You can define processes using proctype proctype A() { byte state; /* local variable */ state = 3 } ; used as a separator not terminator, so no ; after the last statement
Processes • you can also use -> instead of ; byte state = 2; proctype A() { (state==1) -> state=3 } proctype B() { state = state – 1 }
Process Instantiation • You use an init block to identify initial states of the system init { skip } • You can use the init block to instantiate processes init { run A(); run B() } • run is used to start executing a process and can also pass arguments (basic data types) to a process
Atomic sequences • A sequence of statements can be executed atomically using the atomic construct atomic { (state==1) -> state=state+1 }
Message passing • Channels can be used to model transfer of data from one process to another • Channels are basically FIFO message queues • Channels can store tuples of values at each location in the message queue chan qname = [16] of { int } • A channel that stores integer values chan qname = [16] of {int, int, bool} • A channel that stores tuples that consist of two integers and one boolean value
Message passing • Send operations: qname!expr sends the value of the expression expr to the channel named qname • Receive operations: qname?msg retrieves the message from the head of the channel qname and stores it in the variable msg
Rendez-Vous Communication • If the channel size is set to 0 then, the communication corresponds to synchronous communication • Sender and receiver must execute matching send and receive actions at the same time • If the sender (the receiver) reaches the send (the receive) operation before the receiver (the sender) reaches the receive (the send) operation, it has to wait chan port = [0] of {byte}
Control flow: case selection if ::(a!=b) -> option1 ::(a==b) -> option2 fi If more than one guard is executable, then one option is chosen nondeterministically
Control flow: repetition (loops) do :: count = count+1 :: count= count-1 :: (count==0) -> break od Only one option is selected for execution at a time. After that option is executed, the process is repeated.
Enumerated variables • You can define enumerated variables using mtype mtype = {ack, nak, err, next, accept} chan q = [4] of {mtype, mtype, bit, short}
Example Mutual Exclusion Protocol Two concurrently executing processes are trying to enter a critical section without violating mutual exclusion Process 1: while (true) { out: a := true; turn := true; wait: await (b = false or turn = false); cs: a := false; } || Process 2: while (true) { out: b := true; turn := false; wait: await (a = false or turn); cs: b := false; }
Example Mutual Exclusion Protocol in Promela #define cs1 process1@cs #define cs2 process2@cs #define wait1 process1@wait #define wait2 process2@wait #define true 1 #define false 0 bool a; bool b; bool turn; proctype process1() { out: a = true; turn = true; wait: (b == false || turn == false); cs: a = false; goto out; } proctype process2() { out: b = true; turn = false; wait: (a == false || turn == true); cs: b = false; goto out; } init { run process1(); run process2() }
Property automaton generation • Input formula • “[]” means G • “<>” means F • “spin –f” option • generates a Buchi automaton for the input LTL formula % spin -f "! [] (! (cs1 && cs2))“ never { /* ! [] (! (cs1 && cs2)) */ T0_init: if :: ((cs1) && (cs2)) -> goto accept_all :: (1) -> goto T0_init fi; accept_all: skip } % spin -f "!([](wait1 -> <>(cs1)))“ never { /* !([](wait1 -> <>(cs1))) */ T0_init: if :: (! ((cs1)) && (wait1)) -> goto accept_S4 :: (1) -> goto T0_init fi; accept_S4: if :: (! ((cs1))) -> goto accept_S4 fi; } Concatanate the generated never claims to the end of the specification file
SPIN • “spin –a mutex.pml” generates a C program “pan.c” from the specification file • You need to use the “-a” flag to verify temporal logic formulas • The generated pan.c is a C program that implements the on-the-fly nested-depth first search algorithm • You compile “pan.c” and run it to do the model checking (you need to use the “-a” flag when you run the executable) • Spin generates a counter-example trace if it finds out that a property is violated • You can view the counter-example trace using “spin –t –p mutex.pml”
%mutex -a warning: for p.o. reduction to be valid the never claim must be stutter-invariant (never claims generated from LTL formulae are stutter-invariant) (Spin Version 4.2.6 -- 27 October 2005) + Partial Order Reduction Full statespace search for: never claim + assertion violations + (if within scope of claim) acceptance cycles + (fairness disabled) invalid end states - (disabled by never claim) State-vector 28 byte, depth reached 33, errors: 0 22 states, stored 15 states, matched 37 transitions (= stored+matched) 0 atomic steps hash conflicts: 0 (resolved) 2.622 memory usage (Mbyte) unreached in proctype process1 line 18, state 6, "-end-" (1 of 6 states) unreached in proctype process2 line 27, state 6, "-end-" (1 of 6 states) unreached in proctype :init: (0 of 3 states)
Modeling state machines with spin • To model a basic (flat) state machine with Spin we can do the following • Declare the states of the state machine as an mtype • Declare a variable called state that will store the current state of the state machine • Use the init block to initialize the state variable to an initial state of the state machine • Model the transitions of the state machine as a switch cases in a loop do ::(state==s1) -> state=s2 :: ... /* one choice for each transition */ ... od
An example #define state1 state==s1 #define state2 state==s2 #define state3 state==s3 #define state4 state==s4 #define p (state==s1 || state==s4) mtype = {s1, s2, s3, s4}; mtype state; proctype fsm() { do :: state==s1 -> state=s2; :: state==s2 -> state=s3; :: state==s3 -> state=s1; :: state==s3 -> state=s4; :: state==s4 -> state=s3 od } init { state = s3; run fsm() } A simple state machine and the corresponding Promela model (saved it in a file fsm.pml) p p s1 s2 s3 s4
An example • We can check properties such as the following LTL formulas (<> is F and [] is G): <> p (this property holds on our example) [] p (this property does not hold on our example) [] !p (this property does not hold our example either) []<> p (this property holds on our examle)
An example • To check propety <>p we create a never claim for its negation: % spin -f “! <> p” never { /* ! <> p */ accept_init: T0_init: if :: (! ((p))) -> goto T0_init fi; }
An example • Concatenate the never claim to fsm.pml and then do the following: % spin -a fsm.pml % gcc pan.c -o fsm % ./fsm –a • We get the output in the next page
Verification output $ ./fsm –a warning: for p.o. reduction to be valid the never claim must be stutter-invariant (never claims generated from LTL formulae are stutter-invariant) (Spin Version 4.2.6 -- 27 October 2005) + Partial Order Reduction Full statespace search for: never claim + assertion violations + (if within scope of claim) acceptance cycles + (fairness disabled) invalid end states - (disabled by never claim) State-vector 24 byte, depth reached 8, errors: 0 7 states, stored (14 visited) 4 states, matched 18 transitions (= visited+matched) 0 atomic steps hash conflicts: 0 (resolved) 4.879 memory usage (Mbyte) unreached in proctype fsm line 12, state 2, "state = s2" line 13, state 4, "state = s3" line 16, state 10, "state = s3" line 18, state 14, "-end-" (4 of 14 states) unreached in proctype :init: (0 of 3 states) Means that the property holds
An example • Now let’s check the following property [] !p we create a never claim for its negation: % spin -f “! [] ! p” never { /* ! [] ! p */ T0_init: if :: ((p)) -> goto accept_all :: (1) -> goto T0_init fi; accept_all: skip }
An example % ./fsm –a warning: for p.o. reduction to be valid the never claim must be stutter-invariant (never claims generated from LTL formulae are stutter-invariant) pan: claim violated! (at depth 11) pan: wrote test.trail (Spin Version 4.2.6 -- 27 October 2005) Warning: Search not completed + Partial Order Reduction Full statespace search for: never claim + assertion violations + (if within scope of claim) acceptance cycles + (fairness disabled) invalid end states - (disabled by never claim) State-vector 24 byte, depth reached 11, errors: 1 6 states, stored 0 states, matched 6 transitions (= stored+matched) 0 atomic steps hash conflicts: 0 (resolved) 4.879 memory usage (Mbyte) Means that the property is violated
An example • Then we can generate the counter-example trace using “spin –t –p fsm.pml” This is referring to the state of the whole specification This is the variable we declared % spin -t -p fsm.pml Starting :init: with pid 0 Starting :never: with pid 1 Never claim moves to line 32 [(1)] 2: proc 0 (:init:) line 19 "fsm.pml" (state 1) [state = s3] Starting fsm with pid 2 4: proc 0 (:init:) line 20 "fsm.pml" (state 2) [(run fsm())] 6: proc 1 (fsm) line 13 "fsm.pml" (state 5) [((state==s3))] 8: proc 1 (fsm) line 13 "fsm.pml" (state 6) [state = s1] Never claim moves to line 31 [(((state==s1)||(state==s4)))] 10: proc 1 (fsm) line 11 "fsm.pml" (state 1) [((state==s1))] Never claim moves to line 35 [(1)] spin: trail ends after 11 steps #processes: 2 state = s1 11: proc 1 (fsm) line 11 "fsm.pml" (state 2) 11: proc 0 (:init:) line 21 "fsm.pml" (state 3) <valid end state> 11: proc - (:never:) line 36 "fsm.pml" (state 8) <valid end state> 2 processes created