Upload
scott-shepherd
View
229
Download
1
Embed Size (px)
Citation preview
Introduction to SPIN
Radu Iosif ([email protected])
PROMELA (PROcess MEta LAnguage) is:– a language to describe concurrent (distributed)
systems: • network protocols, telephone systems• multi-threaded (-process) programs
– similar with some structured languages (e.g. C, Pascal)
SPIN (Simple Promela INterpreter) is a tool for:– detecting logical errors in the design of systems e.g:
• deadlocks• assertions (e.g. race conditions)• temporal logic formulas (in a future lecture)
Given a PROMELA model (program), SPIN can do:
– a random simulation i.e. it interprets the program• this mode cannot be used in exhaustive verification• useful for viewing error traces
– an exhaustive analysis• considers all possible executions of the program• finds all potential errors, both deadlock and user-specified
Deadlock: – situation in which at least one process remains blocked
forever while waiting for an inexistent event to happen
User specified constraints: – assertions– temporal (never) claims
PROMELA “Hello World”
The simplest erroneous specification
init {
0;
}
init {
printf(“Hello World\n”);
}
The SPIN simulation
init { printf(“Hello World\n”);}
SPIN
0: proc - (:root:) creates proc 0 (:init:)
Hello World
1: proc 0 (:init:) line 3 "pan_in" (state 1) [printf(‘Hello World\\n')]
simulation trace
C:\> spin –p hello.prom
The SPIN analysis (1)
init { 0;} SPIN C:\> spin –a dlock.prom
pan.t pan.m pan.b pan.h pan.c
GCC
pan.exe
The SPIN analysis (2)
pan.exe dlock.prom.trail
SPIN C:\> spin –p -t dlock.prom
#processes: 1 -4: proc 0 (:init:) line 3 "pan_in" (state 1)1 processes created
error trace
OK
ERROR
The PROMELA language
Similar to C, for instance:
• all C pre-processor directives can be used
• definitions of types, variables, processes
•if,do,break,goto control flow constructs
Basic types and ranges
At most one enumeration type
bit, bool 0..1
byte 0..255
short - 2^15 - 1 .. 2^15 - 1
int -2^31 – 1 .. 2^31 - 1Warning: type ranges are OS-
dependent (just like in C)
mtype = {one, two, three};
Record types (user-defined)
• look like C structures
typedef S {
short a, b;
byte x;
};
Variables (same C syntax)
Processes (like C procedures)
• the init process (like main in C)– has no parameters
int x, y;
int z = 0;
mtype m = one;
proctype foo(int x, y; bit b){...}
Scoping rules
– variables are global if declared outside any process
– variables are local a process if declared within its proctype declaration
– local variables shadow globals with the same name
Vectors
– declared like variables:
– indexes are zero-based– scoping rules apply (there might be
global and local vectors)
int vector[32];
Expressions
– logical: ||, &&, !– arithmetic: +, -, /, %– relational: >,<,<=,>=,==,!=
– vector access: v[i]– record access: x.f– process creation: run X()
Statements (1) – are execution steps of processes – an important characteristic is
executability:
For instance:
is the (proper) way of expressing something like:
x <= 10;
while(x <= 10);
Statements (2)
• Expression statements• not executable iff expression evaluates to 0
• Assignment statements• always executable
• Skip statements• always executable• do “nothing” (only change control location)
• Print statements• always executable
Statements (3)
• Assert statements
• always executable• expression evaluates to zero => program
exits
• Statements are atomic• in a concurrent program, each statement is
executed without interleaving with other processes
assert( <expression> );
Control flow (1)• Select construct
• What does it do?• if a (random) choice is executable, continues
execution with the corresponding branch• if no choice is executable, the whole select is not
executable• if more than one choice is executable, we say the
selection is non-deterministic
if
:: <choice1> -> <stat11>; <stat12>; …
:: <choice2> -> <stat21>; <stat22>; …
…
fi;
Control flow (2)• Loop construct
• What does it do?• same as the selection, except that at the
end of a branch it loops back and repeats the choice selection
do
:: <choice1> -> <stat11>; <stat12>; …
:: <choice2> -> <stat21>; <stat22>; …
…
od;
Control flow (3) (more C syntax)
• The else choice• is executable only when no other choice
is executable
• The break statement• transfers control at the end of loop
• The goto statement• transfers control to a labeled location
Traffic light example
mtype = {red, yellow, green};
byte state = green;
init {
do
:: (state == green) -> state = yellow;
:: (state == yellow) -> state = red;
:: (state == red) -> state = green;
od
}
Concurrency• Processes can spawn other processes
using the run expression
proctype foo(int x; byte y) {…}
init {
int pid;
pid = run foo(256, 255);
/* or simply: */
run foo(256, 255);
…
}
Interleaving
• Premises:– two or more processes composed of atomic
statements– one processor shared between processes
• Problems:– worst-case complexity is exponential in no of
processes– improper mutex (locking) may cause race
conditions
Complexity
s11
s12
s21
s22
s12
s11
s21
s21
. . .
• how many states can be reached in this example?
• express this number as function of:
K = number of processes
N = number of states/process
Reducing complexity (1)
• if a statement inside atomic is not executable, transfer temporarily control to another process
s12
s11
s21
s21s11
s12
s21
s22
atomic
. . .
Reducing complexity (2)
• if a statement inside d_step is not executable => error (block inside d_step)
• no if, do, break, goto, run allowed inside d_step (i.e., deterministic step)
s11+s12
s21
s21s11
s12
s21
s22
d_step
. . .
Apprentice example• Good apprentice
• Bad apprentice
int counter = 0;
active[2] proctype incr() {
counter = counter + 1;
}
int counter = 0;
active[2] proctype incr() {
int tmp;
tmp = counter + 1;
counter = tmp;
}
atomic
Mutual exclusion (bad) example
proctype B() {
y = 1;
x == 0;
mutex ++;
mutex --;
y = 0;
}
proctype A() {
x = 1;
y == 0;
mutex ++;
mutex --;
x = 0;
}
proctype monitor() {
assert(mutex != 2);
}
Dekker’s mutual exclusion
proctype A() {
x = 1;
turn = Bturn;
(y == 0) || (turn == Aturn);
mutex ++;
mutex --;
x = 0;
}
proctype B() {
y = 1;
turn = Aturn;
(x == 0) || (turn == Bturn);
mutex ++;
mutex --;
y = 0;
}
proctype monitor() {
assert(mutex != 2);
}
Bakery mutual exclusion
• does verification terminate?
proctype A() {
do
:: 1 -> turnA = 1;
turnA = turnB + 1;
(turnB == 0) || (turnA < turnB);
mutex ++; mutex --;
turnA = 0;
od
}
(Some formal issues)
Formal Concurrent Systems (FCS)
• Mathematical descriptions of concurrent systems
• Important tools for reasoning about such systems
• Composed of states and transitions• Graphical representations of FCS: directed
graphs– nodes represent states, edges are transitions
FCS preliminaries
• Let A,B be two sets• A relation R is a subset of A x B
– we also write aRb for (a, b) in R
• A function F: A B is a relation such that1. for each a A there exists b in B such that aFb2. such b is unique
• Some notation:– [a b]F is a function G such that G(a) = b
and, for all x other than a, G(x) = F(x)
States
• Let P be a set of processes P = {p1, … , pn}
• Let L be a set of control locations L = {l1, …, lm}
• Let loc : P L be a control function
• Let I be a set of variables I = {x1, …, xk }
• Let V be a set of values V = {v1, v2, … }
• Let mem : I V be a memory function
• A state is a pair:S = (loc, mem)
Transitions (1)
• A condition C is a boolean expression on a subset of I
• An assignment A is a pair (x, v) from I x V also denoted by x v
• A transition is a 5-tuple:t = (p, ls, ld, C, A)
where ls and ld are elements of L called source and destination locations
Transitions (2)
• A transition t = (p, ls, ld, C, A) is executable in state s = (loc, mem) iff:– loc(p) = ls and C = true
• The result of executing transition t in state s is– s’ = ([p ld]loc, [A]mem)– also denoted by s t s’
Transition systems (TS)• A transition system is a pair TS = (S, s0, T)
– S is a set of states; s0 S is the initial state
– T is a transition relation (S x S)• A TS can be built from each FCS:
– S = {(loc, mem) | loc: P L, mem : I V}– for each two states s, s’ such that s t s’
for some transition t introduce (s, s’) in T• s1,s2, …, sn, … is an (in)finite execution
sequence of the TS iff:– s1 = s0 (initial state condition)– (si, si+1) T (successor condition)
Labeled transition systems (LTS)• LTS = (, S, s0, )
is the alphabet– S is a set of states; s0 S is the initial
state
– : S x P(S) is a transition function• Also known in compilers as finite automata• s1,a1,s2,a2, …, sn,an,sn+1, … is an
(in)finite execution sequence of the LTS iff– s1 = s0 (initial state condition)
– si+1 (si, ai) (successor condition)
Parallel product of LTSs• Given
– LTS1 = (1, S1, s01, 1), – LTS2 = (2, S2, s02, 2)
• The parallel product of LTS1 and LTS is– LTS1 || LTS2 = (, S, s0, ) where: = 1 U 2– S = S1 x S2; s0 = (s01, s02)– (s1’, s2’) ((s1, s2), a) iff either:
• a 1 and s1’ 1(s1, a) or• a 2 and s2’ 2(s2, a)
Synchronous product of LTSs• Given
– LTS1 = (1, S1, s01, 1), – LTS2 = (2, S2, s02, 2)
• The synchronous product of LTS1 and LTS2 is– LTS1 x LTS2 = (, S, s0, ) where: = 1 2– S = S1 x S2; s0 = (s01, s02)– (s1’, s2’) ((s1, s2), a) iff both hold:
• s1’ 1(s1, a) and• s2’ 2(s2, a)
Execution traces, words and languages (1)• Let F S be a set of states• We say LTS = (, S, s0, , F) accepts a
word w = a1, a2, … over iff there exists an execution sequence of LTS:– = s1, a1, s2, a2, …
such that there exists some state from F that repeats infinitely often in
• L(LTS) is the set of all words accepted by LTS
• Also known as the language of LTS
Execution traces, words and languages (2)• Given
–LTS1 = (1, S1, s01, 1, S1), –LTS2 = (2, S2, s02, 2, S2)
– L(LTS1 || LTS2) is the set of all interleavings between words generated by LTS1 and LTS2
– L(LTS1 x LTS2) = L(LTS1) L(LTS2)
– we say an LTS is empty iff L(LTS) =
(Some formal issues)END
Communication (1)
1. Message passing2. Rendez-vous synchronization
• Both methods rely on channels:
– if dim is 0 then q is a rendez-vous port– otherwise q is an asynchronous
channel
chan q = [<dim>] of {<type>};
chan q; /* just declaration */
Communication (2)
• Send statement
– for rendez-vous channels is executable iff another process is ready to receive at the same time both processes are involved in a rendez-vous
– for asynchronous queues is executable iff the queue is not full
q ! <expr>;
Communication (3)
• Receive statement
– for rendez-vous channels is executable iff another process is ready to send at the same time both processes are involved in a rendez-vous
– for asynchronous queues is executable iff the queue is not empty
q ? <var>;
q ? _;
Communication (4)
• Channel test statement
– same as receive for rendez-vous channels
– for asynchronous queues is executable iff the first value in the queue matches the result of expr
q ? <expr>;
Inter-locking example
chan lock = [1] of bit;
proctype foo(chan q) {
q ? 1;
/* critical section */
q ! 1;
}
init {
lock ! 1;
run foo(lock);
run foo(lock);
}
Recursion example
proctype fact(int n; chan r) {
int tmp;
chan c = [1] of {bit};
if
:: n == 0 -> r ! 1;
:: else ->
run fact(n - 1, c);
c ? tmp; r ! n*tmp;
fi
}
More advanced issues
Fair transition systems (FTS)• FTS = (, S, s0, , J, C)
– a statement labeled by lab is enabled in a state s iff (s, lab)
– J is the justice set; • any statement labeled by lab J cannot be
continuously enabled but not executed beyond a certain point
– C is the compassion set; • any statement labeled by lab J cannot be
enabled infinitely many times but executed only a finite number of times
Weak fairness (1)
proctype foo(){
do
l0: :: (x == 0) ->
l1: y = y + 1;
:: else ->
l2: break;
od
}
proctype bar(){
m0: x = 1;
m1:
}
Pnueli’s ANY-Y
Weak fairness (2)• An execution trace of ANY-Y:
({(foo,l0), (bar,m0)}, {(x,0), (y,0)}), l0, ({(foo,l1), (bar,m0)}, {(x,0), (y,0)}), l1,
({(foo,l0), (bar,m0)}, {(x,0), (y,1)}), l0, ({(foo,l1), (bar,m0)}, {(x,0), (y,1)}), l1,
({(foo,l0), (bar,m0)}, {(x,0), (y,2)}), l0, ({(foo,l1), (bar,m0)}, {(x,0), (y,2)}), l1,
…
• The execution is not acceptable because bar never gets a chance to execute the program doesn’t terminate
• Solution: include m0 into the justice set don’t care about executions in which m0 is continuously enabled but never taken
Strong fairness (1)
proctype foo() {
do
l0: :: lock ? 1;
l1: /* critical */
l2: lock ! 1;
od
}
proctype bar() {
do
m0: :: lock ? 1;
m1: /* critical */
m2: lock ! 1;
od
}Pnueli’s MUX-SEM
Strong fairness (2)• An execution trace of MUX-SEM:
({(foo,l0), (bar,m0)}, {(lock, [1])}), l0, ({(foo,l1), (bar,m0)}, {(lock, [])}), l1,
({(foo,l2), (bar,m0)}, {(lock, [])}), l2, ({(foo,l0), (bar,m0)}, {(lock, [1])}), l0,
({(foo,l1), (bar,m0)}, {(lock, [])}), l1, ({(foo,l2), (bar,m0)}, {(lock, [])}), l2,
({(foo,l0), (bar,m0)}, {(lock, [1])}), …
• Not acceptable because bar never gets a chance to enter the critical section, even though he has infinitely often the chance to add m0 to the compassion set
• NOTE: this is not a justice violation because m0 is not continuously enabled, only from time to time
End labels• An endstate in PROMELA is a state
with no successors• Endstates can be labeled as valid by
introducing labels that start with end– end0,endsome, …
• At the end of each process there is a default valid endstate
• A deadlock is a state with no successors in which at least one process is not in a valid enstate
Timeouts
• A timeout is similar to else or break but:– becomes executable only when no
other transition from any other process is executable
• Provides an escape from deadlock states
Progress labels (a.k.o. strong fairness)• Marked states that must be executed
in order for the program to make progress
• Any infinite execution trace that does not contain at least one progress state is a potential starvation loop
• Like for endstates, label names begin with progress
• Must instruct the model checker to look after non-progress cycles (-l)
Unless construct
{ stat11;
stat12;
…
} unless {
stat21;
stat22;
…
}
• Executes the statements in the main sequence until the first statement in the escape sequence becomes executable