CS 290C: Formal Models for Web Software Lecture 3:

advertisement
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
– 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
1. 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
2. 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:
1. How are we going to characterize properties of
navigation models?
• For this we will briefly discuss temporal logics
2. 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:
Invariant p
:
Gp
(aka
p)
Eventually p
:
Fp
(aka
p)
Next p
:
Xp
(aka
p)
p Until q
:
pUq
,,
(Globally)
(Future)
(neXt)
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
x |= p
x |= p  q
x |= p  q
iff
iff
iff
iff
L(x0, p) = True, where p  AP
not x |= p
x |= p and x |= q
x |= p or x |= q
x |= X p
x |= G p
x |= F p
x |= p U q
iff
iff
iff
iff
x1 |= p
for all i  0, xi |= p
there exists an i  0 such that xi |= p
there exists an i  0 such that xi |= q and
for all 0  j < i, xj |= p
LTL Properties
...
Xp
p
...
Gp
p
p
p
p
p
...
Fp
pUq
p
p
...
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 =  (Fp) =  (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)
p
p s1
s2
s3
s4
T |= X p
T |= F p
T |=  G p
T |= F  p
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
true
Gp
p
p
true
Fp
G (F p)
p
p
p
p
p
p
These are specific type of automata that accepts infinite
strings (they are called Buchi autoamata)
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 counterexample) 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;
int state;
/* declares a boolean array */
/* 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
% 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)))“
• Input formula
“[]” means G
“<>” means F
• “spin –f” option
generates a Buchi
automaton for the
input LTL formula
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
acceptance
cycles
invalid end states
+
+ (if within scope of claim)
+ (fairness disabled)
- (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
A simple state machine
and the corresponding
Promela model
(saved it in a file
fsm.pml)
p
p s1
s2
s3
s4
#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()
}
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
acceptance
cycles
invalid end states
+
+ (if within scope of claim)
+ (fairness disabled)
- (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
% spin -t -p fsm.pml
we declared
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
Download