Explicit State Model Checker  Represents the system as a finite state machine  Visits each reachable state (state space) explicitly Promela/SPIN (using Nested DFS)  Performs on-the-fly computation Acknowledgements:  Uses partial order reduction These notes used some of  Efficient memory usage the material presented by ªState compression Flavio Lerda as part of Ed ªBit-state hashing Clarke’s model-checking  Version 4: course ªUninterpreted C code can be used as part of Promela model •3 SPIN High Level Organization  For checking correctness of process interactions ªSpecified using buffered channels, shared variables or combination LTL formula Promela Model ªFocus: asynchronous control in software systems LTL Translator ªPromela – program-like notation for specifying design choices Buchi Automaton ¾Models are bounded and have countably many distinct behaviors Buchi Translator  Promela Parser Generate a C program that performs an efficient The Buchi automaton is online verification of the system’s correctness turned into a Promela Abstract Syntax Tree process and composed properties Automata Automata with the rest of the system. Generator The generated verifier is  Types of properties: C Generatorspecific to the model and property we started with. ªDeadlock, violated assertions, unreachable code C Code ªSystem invariants, general LTL properties C Compiler Pan Verifier  Random simulations of the system’s execution Verification Result  “Proof approximation” •2 •4 1 2 Promela (Process Meta Language) Process Instantiation  Need to execute processes  Asynchronous composition of independent processes ªproctype only defines them  How to do it?  Communication using channels and global ªBy default, process of type always executes variables init ªrun starts processes  Non-deterministic choices and interleavings ªAlternatively, define them as active (see later)  Based on Dijkstra’s guarded command language  Processes can receive parameters ªEvery statement guarded by a condition and blocks until condition ª all basic data types and message channels. becomes true ªData arrays and process types are not allowed. Example: Example: while (a != b) proctype A (byte state; short foo) skip /* wait for a == b */ { (state == 1) -> state = foo } vs init (a == b) { run A(1, 3) } •5 •7 Process Types Example  State of variable or message channel can only be  As mentioned earlier, no distinction between a changed or inspected by processes (defined statement and condition. using proctype) bool a, b;  ; and -> are statement separators with same proctype p1() semantics. { a = true; ª-> used informally to indicate causal relation between statements a & b; These statements are enabled only if both a and b are true. Example: a = false; byte state = 2; } In this case b is always false proctype A() proctype p2() and therefore there is a { (state == 1) -> state = 3 { deadlock. } b = false; proctype B() a & b; { state = state -1 b = true; } } init { a = false; b = false; run p1(); run p2(); }  state here is a global variable •6 •8 3 4 An Example Other constructs mtype = { NONCRITICAL, TRYING, CRITICAL }; At most one mtype can be  Do loops mtype state[2]; declared proctype process(int id) { beginning:  Communication over channels noncritical: state[id] = NONCRITICAL; proctype sender(chan out) if { :: goto noncritical; NC :: true; int x; fi; trying: if state[id] = TRYING; T ::x=0; if :: goto trying; ::x=1; :: true; fi fi; C critical: out ! x; state[id] = CRITICAL; if } :: goto critical; :: true; fi; goto beginning;} init { run process(0); run process(1) } •9 •11 Other constructs Other constructs  Do loops  Do loops do  Communication over channels :: count = count + 1; :: count = count - 1;  Assertions :: (count == 0) -> break od proctype receiver(chan in) { int value; in ? value; assert(value == 0 || value == 1) } •10 •12 5 6 Other constructs Message Passing Example proctype A(chan q1)  Do loops { chan q2;  Communication over channels q1?q2; q2!123  Assertions } proctype B(chan qforb)  Atomic Steps { int x; qforb?x; int value; proctype increment() print(“x=%d\n”, x) { atomic } { x = value; init { x = x + 1; chan qname = [1] of {chan }; value = x; chan qforb = [1] of {int }; } run A(gname); } run B(qforb); qname!qforb } Prints: 123 •13 •15 Message Passing Randez-vous Communications chan qname = [16] of {short}  Buffer of size 0 – can pass but not store qname!expr – writing (appending) to channel messages qname?expr – reading (from head) of the channel ªMessage interactions by definition synchronous – “peaking” (without removing content) qname??expr Example: qname!!expr – checking if there is room to write #define msgtype 33 can declare channel for exclusive read or write: chan name = [0] of { byte, byte }; chan in, out; xr in; xs out; proctype A() { name!msgtype(123); qname!exp1, exp2, exp3 – writing several vars name!msgtype(121); /* non-executable */ qname!expr1(expr2, expr3) – type and params } qname?vari(var2, var3) proctype B() { byte state; qname?cons1, var2, cons2 – can send constants name?msgtype(state) ªLess parameters sent than received – others are undefined } ªMore parameters sent – remaining values are lost init ªConstants sent must match with constants received { atomic { run A(); run B() } •14 } •16 7 8 Randez-Vous Communications (Cont’d) Example Cont’d  If channel name has zero buffer capacity: mtype = {ack, nak, err, next, accept}; ªHandshake on message msgtype and transfer of value 123 to proctype transfer (chan in, out, chin, chout) variable state. { byte o, I; ªThe second statement will not be executable since no matching in?next(o); receive operation in B do  If channel name has size 1: :: chin?nak(I) -> ªProcess A can complete its first send but blocks on the second out!accept(I); since channel is filled. chout!ack(o) ªB can retrieve this message and complete. :: chin?ack(I) -> ªThen A completes, leaving the last message in the channel out!accept(I); in?next(o);  If channel name has size 2 or more: chout!ack(o) ªA can finish its execution before B even starts :: chin?err(I) -> chout!nak(o) od •17 } •19 Example – protocol Example (Cont’d)  Channels Ain and Bin init ªto be filled with token messages of type next and arbitrary values { chan AtoB = [1] of { mtype, byte }; (ASCII chars)… chan BtoA = [1] of { mtype, byte }; ª by unspecified background processes: the users of the transfer service chan Ain = [2] of { mtype, byte }; chan Bin = [2] of { mtype, byte };  These users can also read received data from the channels Aout and Bout chan Aout = [2] of { mtype, byte };  The channels are initialized in a single atomic chan Bout = [2] of { mtype, byte }; statement… ªAnd started with the dummy err message. atomic { run transfer (Ain, Aout, AtoB, BtoA); run transfer (Bin, Bout, BtoA, AtoB); } Ain!next(0); •18 AtoB!err(0) •20 9 10 Mutual Exclusion Mutual Exclusion in SPIN  Peterson’s solution to the mutual exclusion problem _pid: bool turn, flag[2]; Identifier of the process active [2] proctype user() assert: Checks that there are only { at most two instances with assert(_pid == 0 || __pid == 1); identifiers 0 and 1 flag =1 0 again: flag[_pid] = 1; turn = 1 - _pid; turn=0 flag0=0 (flag[1 - _pid] == 0 || turn == _pid); flag1 == 0 || turn == 1 /* critical section */ flag1 != 0 && turn != 1 Critical flag[_pid] = 0; Section goto again; } •21 •23 Mutual Exclusion in SPIN Mutual Exclusion in SPIN bool turn, flag[2]; byte ncrit; ncrit: bool turn; Counts the number of active [2] proctype user() processes in the critical section bool flag[2]; { proctype mutex0() { assert(_pid == 0 || __pid == 1); again: again: flag[_pid] = 1; flag[0] = 1; flag0=1 turn = 1; turn = 1 - _pid; (flag[1 - _pid] == 0 || turn == _pid); (flag[1] == 0 || turn == 0); turn=1 flag0=0 /* critical section */ flag == 0 || turn == 0 ncrit++; flag[0] = 0; 1 assert(ncrit == 1); /* critical sectionassert: */ flag != 0 && turn != 0 goto again; 1 ncrit--; Checks that there is always } at most one process in the Critical critical section flag[_pid] = 0; Section goto again; •22 •24 } 11 12 Verification Mutual Exclusion in SPIN bool turn, flag[2];  Generate, compile and run the verifier byte ncrit; ª to check for deadlocks and other major problems: active [2] proctype user() { $ spin –a mutex assert(_pid == 0 || __pid == 1); $ cc –O pan pan.c again: flag[_pid] = 1; $ pan turn = 1 - _pid; full statespace search for: (flag[1 - _pid] == 0 || turn ==_pid); assertion violations and invalid endstates vector 20 bytes, depth reached 19, errors: 0 ncrit++; 79 states, stored /* critical section */ 0 states, linked ncrit--; 38 states, matched total: 117 hash conflicts: 4 (resolved) flag[_pid] = 0; (size s^18 states, stack frames: 3/0) goto again; } unreached code _init (proc 0); reached all 3 states active proctype monitor() unreached code P (proc 1): { assert (ncrit == 0 || ncrit == 1) } reached all 12 states •25 •27 Mutual Exclusion Finally,  Verifier: Assertion can be violated  Can specify an LTL formula and run the model- ªCan use -t -p to find out the trace checker ¾Or use XSpin Example: #define p count <= 1  Another way of catching the error ªLTL claim: ªHave another monitor process ran in parallel [] p ªAllows all possible relative timings of the processes  Note: all variables in LTL claims have to be global! ªElegant way to check validity of system invariant  LTL claim gets translated into NEVER claim and stored either in .ltl file or at the end of model file ªOnly one LTL property can be verified at a time  Parameters can be set using XSpin ªDepth of search,
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages15 Page
-
File Size-