0

I am trying to formally verify mutual exclusion on the following Promela Model:

/* Mutex with (bugged) Peterson algorithm */

bool flag[2];
int turn = -1;

active [2] proctype agent() {
    bool in_cs;
    int other = 1 - _pid;

    do
        :: true ->

            /* trying section */
            turn = other;
            flag[_pid] = true;
            !( flag[other] && (turn == other));

            /* critical section */
            in_cs = true;
            printf("Agent %d in CS\n", _pid);
            in_cs = false;

            /* exit section */
            flag[_pid] = false;
    od;
}

ltl mutex { [] ! (agent[0]:in_cs && agent[1]:in_cs) }

To verify it, I use the following chain of commands:

~$ spin -a test.pml ; gcc -o run pan.c -DNOREDUCE ; ./run -a -N p1

which prints the following output:

...
Full statespace search for:
    never claim             + (mutex)
    assertion violations    + (if within scope of claim)
    acceptance   cycles     + (fairness disabled)
    invalid end states      - (disabled by never claim)

State-vector 40 byte, depth reached 53, errors: 0
...

Q: i know for a fact that the Promela Model does not satisfy mutual exclusion, but Spin claims that it does. Why is it?


NOTE: I added option -DNOREDUCE when compiling with gcc because Spin 6.4.8 prints a warning message requesting me to do so if I don't:

~$ spin -a test.pml ; gcc -o run pan.c ; ./run -a -N p1
...
pan.c: In function ‘main’:
pan.c:9478:3: warning: #warning p.o. reduction not compatible with remote varrefs (use -DNOREDUCE) [-Wcpp]
  #warning p.o. reduction not compatible with remote varrefs (use -DNOREDUCE)
   ^~~~~~~
...
Patrick Trentin
  • 7,126
  • 3
  • 23
  • 40

1 Answers1

0

Here is the solution:

The problem here is that to disable partial order reduction you not only have to compile with -DNOREDUCE but also generate the model while disabling statement merging (merging of subsequent local actions) -- which is also a partial order reduction strategy. So, for the second example you also get the counter-example if you do:

spin -o3 -a test.pml; gcc -DNOREDUCE -o pan pan.c; ./pan -a

[G. H., private communication]

The output of the suggested solution matches our expectation:

~$ spin -o3 -a test.pml ; gcc -o run pan.c -DNOREDUCE ; ./run -a -N p1
...
pan:1: assertion violated  !( !( !((agent[0].in_cs&&agent[1].in_cs)))) (at depth 55)
pan: wrote test.pml.trail

...

Full statespace search for:
    never claim             + (mutex)
    assertion violations    + (if within scope of claim)
    acceptance   cycles     + (fairness disabled)
    invalid end states  - (disabled by never claim)

State-vector 40 byte, depth reached 69, errors: 1
...

Alternatively, one can circumvent the problem by using label remote references instead of variable remote references, e.g.:

/* Mutex with (bugged) Peterson algorithm */

bool flag[2];
int turn = -1;

active [2] proctype agent() {
    int other = 1 - _pid;

    do
        :: true ->

            /* trying section */
            turn = other;
            flag[_pid] = true;
            !( flag[other] && (turn == other));

            /* critical section */
cs:
            printf("Agent %d in CS\n", _pid);

            /* exit section */
            flag[_pid] = false;
    od;
}

ltl mutex { [] ! (agent[0]@cs && agent[1]@cs) }

With this Model, we find a counter-example, as expected:

~$ spin -search test.pml
...
pan:1: assertion violated  !( !( !(((agent[0]._p==cs)&&(agent[1]._p==cs))))) (at depth 28)
pan: wrote test.pml.trail
...
Patrick Trentin
  • 7,126
  • 3
  • 23
  • 40