What is SPIN(Simple Promela Interpreter) Lecture XX SPIN and Promela A tool for analyzing mels of reactive systems Mels described in Promela Language with concurrent processes, Communication via channels, Analysis by Simulation Mel checking Several optimizations implemented most efcient tool for explicit-state mel checking 1 2 Material About SPIN SPIN Home page http://spinroot.com/spin/ Contains manuals, reference material, and tutorial Books about SPIN G.J. Holzmann SPIN MODEL CHECKER Primer and Reference Manual, G.J. Holzmann Design and Validation of Computer Protocols,, Prentice Hall 1991, older book, available on the Internet Elements of Promela Language for dening nite-state transition systems Data types with precisely dened nite mains Bits, integers, arrays, messages Processes, which can be dynamically created Communication via global variables or communication channels Simple control constructs 3 4 ypical Structure of Promela Mel Basic Variables and ypes Promela mel consists of type declarations channel declarations variable declarations process declarations init process mtype = {msg, ack; chan tos = chan tor = bool flag; proctype Sender () { proctype Receiver () { Basic types Array declaration Array access Records type denition Record declaration Record access Enumeration type f. messages bit [0.. 1] bool [0.. 1] byte [0.. 255] short [-2 15.. 2 15-1] int [-2 31.. 2 31-1] byte anarray[24]; anarray[v] = anarray[3]; typedef Msg{ byte a[3], b; chan p Msg astruct astruct.a[1] mtype = {ack, nak, err, next 5 6
Expressions Basic Statements Operators + - * / % ^ > >= < <= ==!=! && & - >> << ++ -- Expressions Assignments No-Op (y == false x > 9) y = 34 % 3 anarray[0] = anarray[3] * anarray[(v+2)/4] skip Conditional expression (v >= 0 -> v : -v) Goto goto label Operations on channel identers len(qid) empty(qid) full(qid) nempty(qid) nfull(qid) 7 printf Print (only in simulation) All basic statements are either executable (enabled) or blocked (disabled) (of course, depending on values of variables, etc.) Expressions are also statements Blocked evaluated to 0, otherwise executable In this way, expressions/statements can be used as guards 8 Compound Statements Compound Statements (ctd.) Sequential composition Selection test == 1 ; state = state + 1 test == 1 -> state = state + 1 :: (a == b) -> state = state + 1 :: (a!= b) -> state = state 1 equivalent Repetition :: (m > n) -> m = m - n :: (m < n) -> n = n m :: (m == n) -> break ; printf ( GCD = %d\n, m) :: (a == b) -> state = state + 1 -> state = state 1 Selection can be nonderministic :: input? offhook :: (a == b) -> b = 3 ; goto onhook :: output! wakeup :: b = 3 /*any statement can be guard*/ 9 10 Processes and process types Name proctype Sender(chan in; chan out) { Local variable declarations bit sndb, rcvb; :: out! data(sndb) -> in? ack(rcvb); formal parameters :: sndb == rcvb > sendb = 1-sndB -> skip Processes dened by proctype denitions A process type may be instantiated several times Each process has its local state (pc, local variables) Processes execute concurrently, by interleaving Process instantiations Processes are created by run statement/expression run returns process id Processes execute their rst statement some time after creation Processes can be statically created at initialization time (no formal parameters allowed) proctype Foo(byte x) { int pid = run Foo(2); run Foo(27) active[3] proctype Bar(){ 11 12
Communication Channels Communication Channels (ctd.) Channels used for passing messages Asynchronous (buffered, default is FIFO) Synchronously (rendez-vous) Declaring synchronous (rendez-vous) channel w. capacity 0 chan synch[3] = [0] of {mtype, int chan qid = [4] of {mtype, int, byte chan synch[3] = [0] of {mtype, int name capacity types of messages Sending qid! var1, const, var qid! err(const, var) matched Receiving qid? err(const, var) assigned Non-mying receive qid? [err, const, var] Sorted send/receive (inserts lexicographically, receives any element) qid!! err(const, var) qid?? err(const, var) 13 14 Message ransmission Protocol Alternating Bit Protocol (version 1) mtype = { m0, m1, ack proctype Receiver{ mtype = { msg, ack ; Rec0: :: StoR?any -> skip /* loss */ chan s_r = [2] of {mtype, byte, bit; bit rbit, seqno = 0; :: StoR?m0 -> RtoS!ack; chan r_s = [2] of {mtype, bit ; goto Rec1 proctype Sender{ r_s! ack(seqno); Send0: Rec1: -> /* timeout */ :: StoR?any -> skip /* loss */ :: seqno == rbit -> StoR!m0 :: StoR?m1 -> RtoS!ack; rbit = 1 rbit :: RoS?ack -> /* rec ack */ goto Rec0 :: s_r! msg(data, sbit) -> SoR!m1; r_s? ack(seqno); goto Send1 ; Send1: sbit = 1 sbit; -> /* timeout */ chan StoR = [1] of { mtype ; StoR!m1 chan RtoS = [1] of { mtype ; :: RoS?ack -> /* rec ack */ SoR!m0; StoR!m0; /* start */ goto Send0 run Sender; run Receiver 15 16 Alternating Bit Protocol (version 1 altern) AB Protocol (version 2, with losses ) mtype = { msg, ack ; proctype Receiver() { mtype = { msg, ack ; chan s_r = [2] of {mtype, byte, bit; bit rbit, seqno = 0; chan s_r = [2] of {mtype, byte, bit; bit rbit = 1, seqno = 0; chan r_s = [2] of {mtype, bit ; chan r_s = [2] of {mtype, bit ; proctype Sender() { r_s! ack(seqno); :: r_s! ack(seqno) :: seqno == rbit -> rbit = 1 rbit ; :: s_r! msg(data, sbit) -> :: s_r! msg(data, sbit) -> r_s? ack(seqno); r_s? ack(seqno); :: seqno == rbit -> rbit = 1 rbit sbit = 1 sbit; sbit = 1 sbit; run Sender(); run Receiver() 17 18
AB Protocol (v 3, w.retransmissions ) AB Protocol (v 4, checking data delivery) mtype = { msg, ack ; chan s_r = [2] of {mtype, byte, bit; chan r_s = [2] of {mtype, bit ; :: s_r! msg(data, sbit) bit rbit = 1; :: s_r? msg (recd, rbit) mtype = { msg, ack ; chan s_r = [2] of {mtype, byte, bit; chan r_s = [2] of {mtype, bit ; :: s_r! msg(data, sbit) assert(recd == expected); 19 20 AB Protocol (v 4b, checking data delivery) AB Protocol (v 5, progress) mtype = { msg, ack ; chan s_r = [2] of {mtype, byte, bit; chan r_s = [2] of {mtype, bit ; :: data < 10 -> s_r! msg(data, sbit) assert(recd == expected); mtype = { msg, ack ; chan s_r = [2] of {mtype, byte, bit; chan r_s = [2] of {mtype, bit ; :: data < 10 -> s_r! msg(data, sbit) progress: assert(recd == expected); 21 22 AB Protocol (v 6, progress) AB Protocol (v 7, acceptance) mtype = { msg, ack ; chan s_r = [2] of {mtype, byte, bit; chan r_s = [2] of {mtype, bit ; :: data < 10 -> s_r! msg(data, sbit) :: (1) -> progress1: skip progress: assert(recd == expected); :: (1) -> progress2: skip mtype = { msg, ack ; chan s_r = [2] of {mtype, byte, bit; chan r_s = [2] of {mtype, bit ; :: s_r! msg(data, sbit) Slabel: data < 10 -> Rlabel: rbit = 1 - rbit ; assert(recd == expected) ; expected < 10 -> 23 24
Vikings problem Problem with Atomicity (* insert a mel of Vikings problem *) Only basic statements are atomic Q: What is the nal value of state? byte state = 1; proctype A() { state == 1 -> state++ proctype B() { state == 1 -> state-- run A() ; run B() 25 26 Solution: atomic-construct Other use of atomic{ A process whose control is inside atomic{ executes without being interrupted by other processes NOE: Make sure that such a sequence cannot be blocked inside (after the rst statement). In that case, Promela will suspend the process, and you get unintended semantics. byte state = 1; proctype A() { state == 1 -> state++ proctype B() { state == 1 -> state-- run A() ; run B() o group complex manipulation into single transition If the manipulation is deterministic and always exits at the end d_step { is more efcient cnt = 0 ; :: (cnt < Max) -> z[cnt] = 3; cnt++ :: (cnt >= Max) -> break d_step { cnt = 0 ; :: (cnt < Max) -> z[cnt] = 3; cnt++ :: (cnt >= Max) -> break 27 28 Else and imeout Useful Macros else is enabled no other statement in the same process is enabled timeout is enabled no other statement in the entire Promela mel is enabled skip is best to use we want to be sure to analyze the effect of possibly premature timeout. :: (m > n) -> m = m - n :: (m < n) -> n = n m -> break ; printf ( GCD = %d\n, m) :: input? offhook :: input? ringing :: timeout -> output! wakeup Od :: input? offhook :: input? ringing -> output! wakeup 29 IF without else branch Allows to write FOR loop Allows to write which means #dene IF :: #dene FI IF b -> x++ FI #dene FOR(i,l,h) i = l ; :: i < h -> #dene ROF(i,l,h) ;i++ :: i >= h -> break FOR(i,0,N) run proc(i) ROF(i,0,N) i = 0 ; :: i < N -> run proc(i) :: i >= N -> break 30
Specying invariant properties Peterson-Fischer Mutual Exclusion Always executable If v <= 2 is false, SPIN exits with error Used to check invariants assert (v <= 2) #dene true 1 #dene false 0 #dene turn1 false #dene turn2 true bool y1, y2, t; byte mutex = 0; proctype P1() { l1: y1 = true; l2: t = turn2; l3: (y2 == false t == turn1) ; assert (mutex <= 1) ; l4: /* critical section */ mutex -- ; atomic{ y1 = false ; goto l1 proctype P2() { m1: y2 = true; m2: t = turn1; m3: (y1 == false t == turn2) ; assert (mutex <= 1) ; m4: /* critical section */ mutex-- ; atomic{ y2 = false ; goto m1 run P1() ; run P2() 31 32 Checking by monitor Checking deadlocks #dene true 1 #dene false 0 #dene turn1 false #dene turn2 true bool y1, y2, t; byte mutex = 0; proctype P1() { l1: y1 = true; l2: t = turn2; l3: (y2 == false t == turn1) ; l4: /* critical section */ mutex -- ; atomic{ y1 = false ; goto l1 proctype P2() { m1: y2 = true; m2: t = turn1; m3: (y1 == false t == turn2) ; m4: /* critical section */ mutex-- ; atomic{ y2 = false ; goto m1 active proctype monitor() { assert (mutex <= 1) run P1() ; run P2() #dene true 1 #dene false 0 #dene turn1 false #dene turn2 true bool y1, y2, t; byte mutex = 0; proctype P1() { l1: y1 = true; l2: skip ; l3: (y2 == false) ; l4: /* critical section */ mutex -- ; atomic{ y1 = false ; goto l1 proctype P2() { m1: y2 = true; m2: skip ; m3: (y1 == false) ; m4: /* critical section */ mutex-- ; atomic{ y2 = false ; goto m1 active proctype monitor() { assert (mutex <= 1) run P1() ; run P2() 33 34 Checking progress by progress-labels Checking progress (ctd.) #dene MAX 5 mtype = { mesg, ack, nak, err ; proctype sender(chan in, out) { byte o, s, r; o=max-1; :: o = (o+1)%max; /* next msg */ again: :: out!mesg(o,s) /* send */ :: (1) -> progress1: out!err(0,0) /* distort */ proctype receiver(chan in, out) { byte i; /* actual input */ byte s; /* actual seqno */ byte es; /* expected seqno */ byte ei; /* expected input */ :: in?mesg(i, s) -> :: (s == es) -> assert(i == ei); progress: es = 1 - es; ei = (ei + 1)%MAX; chan s_r = [1] of { mtype,byte,byte ; chan r_s = [1] of { mtype,byte,byte ; run sender(r_s, s_r); run receiver(s_r, r_s) :: (1) -> progress2: skip /* or lose */ ; :: timeout -> goto again :: in?err(0,0) -> goto again :: in?nak(r,0) -> goto again :: in?ack(r,0) -> :: (r == s) -> goto progress :: (r!= s) -> goto again ; progress: s = 1-s /* toggle seqno */ /* send, */ :: out!ack(s,0) /* distort */ :: (1) -> out!err(0,0) :: (s!= es) -> /* send, */ :: out!nak(s,0) /* distort */ :: (1) -> out!err(0,0) :: in?err(0,0) -> out!nak(s,0) 35 36
Progress labels: improved version Automata properties: never claims #dene MAX 5 mtype = { mesg, ack, nak, err ; proctype sender(chan in, out) { byte o, s, r; o=max-1; :: o = (o+1)%max; /* next msg */ again: :: out!mesg(o,s) /* send */ :: (1) -> progress1: out!err(0,0) /* distort */ :: (1) -> progress2: skip /* or lose */ ; :: timeout -> goto again :: in?err(0,0) -> goto again :: in?nak(r,0) -> goto again :: in?ack(r,0) -> :: (r == s) -> goto progress :: (r!= s) -> goto again ; progress: s = 1-s /* toggle seqno */ proctype receiver(chan in, out) { byte i; /* actual input */ byte s; /* actual seqno */ byte es; /* expected seqno */ byte ei; /* expected input */ :: in?mesg(i, s) -> :: (s == es) -> assert(i == ei); progress: es = 1 - es; ei = (ei + 1)%MAX; /* send, */ :: out!ack(s,0) /* distort */ :: (1) -> progress1: out!err(0,0) :: (1) -> progress2: skip :: (s!= es) -> /* send, */ :: out!nak(s,0) /* distort */ :: (1) -> progress3: out!err(0,0) :: (1) -> progress4: skip :: in?err(0,0) -> out!nak(s,0) 37 Automata specications can be given in Promela as Never claims, e.g., ( p -> p ) p p never { :: p -> break ; ::!p -> break Never claims execute in lock-step with the rest of the Promela mel Accept they reach the end 38 Buchi Automata as never claims Accepting states designated by labels acceptxxxxx ( p /\ q) p /\ q q never { :: p &&!q -> break ; accept: ::!q he never claim accepts the Promela mel has cycle with only!q hen SPIN reports a violating cycle. 39