2

If I write the following code in Promela and run it in Spin in verifier mode it ends with 0 errors. It does report that toogle and init had unreached states, but those seem to be only warnings.

byte x = 0; byte y = 0;
active proctype toggle() {
    do
    :: x == 1 -> x = 0
    :: x == 0 -> x = 1
    od
}
init {
    (y == 1);
}

I was confused by this because I thought this would give me a 'invalid end state' error. If I change the body of the toogle proctype with a simple skip statement it does error out as I expected.

Why is this? Is there a way to force the simulator to report the infinite loop as an error?

Regarding the 'unreached in proctype' messages, adding an end label to the do loop doesn't seem to do anything.

I am running spin 6.5.0 and ran the following commands:

spin.exe -a test.pml
gcc -o pan pan.c
pan.exe

These are the outputs, for reference.

With do loop:

pan.exe

(Spin Version 6.5.0 -- 1 July 2019)
        + Partial Order Reduction

Full statespace search for:
        never claim             - (none specified)
        assertion violations    +
        acceptance   cycles     - (not selected)
        invalid end states      +

State-vector 20 byte, depth reached 3, errors: 0
        4 states, stored
        1 states, matched
        5 transitions (= stored+matched)
        0 atomic steps
hash conflicts:         0 (resolved)

Stats on memory usage (in Megabytes):
    0.000       equivalent memory usage for states (stored*(State-vector + overhead))
    0.292       actual memory usage for states
   64.000       memory used for hash table (-w24)
    0.343       memory used for DFS stack (-m10000)
   64.539       total actual memory usage


unreached in proctype toggle
        ..\test2.pml:7, state 8, "-end-"
        (1 of 8 states)
unreached in init
        ..\test2.pml:10, state 2, "-end-"
        (1 of 2 states)

pan: elapsed time 0.013 seconds
pan: rate 307.69231 states/second

With skip:

pan.exe
pan:1: invalid end state (at depth 0)
pan: wrote ..\test2.pml.trail

(Spin Version 6.5.0 -- 1 July 2019)
Warning: Search not completed
        + Partial Order Reduction

Full statespace search for:
        never claim             - (none specified)
        assertion violations    +
        acceptance   cycles     - (not selected)
        invalid end states      +

State-vector 20 byte, depth reached 1, errors: 1
        2 states, stored
        0 states, matched
        2 transitions (= stored+matched)
        0 atomic steps
hash conflicts:         0 (resolved)

Stats on memory usage (in Megabytes):
    0.000       equivalent memory usage for states (stored*(State-vector + overhead))
    0.293       actual memory usage for states
   64.000       memory used for hash table (-w24)
    0.343       memory used for DFS stack (-m10000)
   64.539       total actual memory usage



pan: elapsed time 0.015 seconds
pan: rate 133.33333 states/second
Patrick Trentin
  • 7,126
  • 3
  • 23
  • 40
tgonzalez89
  • 621
  • 1
  • 6
  • 26

1 Answers1

3

In this example

byte x = 0; byte y = 0;
active proctype toggle() {
    do
    :: x == 1 -> x = 0
    :: x == 0 -> x = 1
    od
}
init {
    (y == 1);
}

the init process is blocked forever (because y == 1 is always false), but the toggle process can always execute something. Therefore, there is no invalid end state error.

Instead, in this example

byte x = 0; byte y = 0;
active proctype toggle() {
    skip;
}
init {
    (y == 1);
}

the init process is still blocked forever, but the toggle process can execute its only instruction skip; and then terminate. At this point, none of the remaining processes (i.e. only init) has any instruction it can execute, so Spin terminates with an invalid end state error.

~$ spin -a -search test.pml
pan:1: invalid end state (at depth 0)
pan: wrote test.pml.trail

(Spin Version 6.5.0 -- 17 July 2019)
...
State-vector 20 byte, depth reached 1, errors: 1
...

Is there a way to force the simulator to report the infinite loop as an error?

Yes. There are actually multiple ways.

The simplest approach is to use option -l of Spin:

~$ spin --help
...
-l: search for non-progress cycles
...

With this option, Spin reports any infinite-loop which does not contain any state with a progress label.

This is the output on your original problem:

~$ spin -search -l test.pml
pan:1: non-progress cycle (at depth 2)
pan: wrote test.pml.trail

(Spin Version 6.5.0 -- 17 July 2019)
...
State-vector 28 byte, depth reached 9, errors: 1
...

~$ spin -t test.pml
spin: couldn't find claim 2 (ignored)
  <<<<<START OF CYCLE>>>>>
spin: trail ends after 10 steps
#processes: 2
        x = 0
        y = 0
 10:    proc  1 (:init::1) test.pml:10 (state 1)
 10:    proc  0 (toggle:1) test.pml:5 (state 4)
2 processes created

An alternative approach is to use LTL model checking. For instance, you may state that at some point the number of processes (see _nr_pr) that are in execution becomes equal to 0 (or more, if you admit some infinite loops), or check that a particular process terminates correctly using remote references.

Both cases are contained in the following example:

byte x = 0; byte y = 0;
active proctype toggle() {
    do
    :: x == 1 -> x = 0
    :: x == 0 -> x = 1
    od;
end:
}
init {
    (y == 1);
}

// sooner or later, the process toggle
// with _pid == 0 will reach the end
// state
ltl p1 { <> toggle[0]@end };

// sooner or later, the number of processes
// that are currently running becomes 0,
// (hence, there can be no infinite loops)
ltl p2 { <> (_nr_pr == 0) };

Both the first

~$ spin -a -search -ltl p1 test.pml
~$ spin -t test.pml
ltl p1: <> ((toggle[0]@end))
ltl p2: <> ((_nr_pr==0))
  <<<<<START OF CYCLE>>>>>
Never claim moves to line 4 [(!((toggle[0]._p==end)))]
spin: trail ends after 8 steps
#processes: 2
        x = 0
        y = 0
        end = 0
  8:    proc  1 (:init::1) test.pml:10 (state 1)
  8:    proc  0 (toggle:1) test.pml:3 (state 5)
  8:    proc  - (p1:1) _spin_nvr.tmp:3 (state 3)
2 processes created

and the second

~$ spin -a -search -ltl p2 test.pml
~$ spin -t test.pml
ltl p1: <> ((toggle[0]@end))
ltl p2: <> ((_nr_pr==0))
  <<<<<START OF CYCLE>>>>>
Never claim moves to line 11    [(!((_nr_pr==0)))]
spin: trail ends after 8 steps
#processes: 2
        x = 0
        y = 0
        end = 0
  8:    proc  1 (:init::1) test.pml:10 (state 1)
  8:    proc  0 (toggle:1) test.pml:3 (state 5)
  8:    proc  - (p2:1) _spin_nvr.tmp:10 (state 3)
2 processes created

LTL properties are found to be false.


Regarding the 'unreached in proctype' messages, adding an end label to the do loop doesn't seem to do anything.

The end label(s) are used to remove the "invalid end state" error that would be otherwise be found.

For example, modifying your previous example as follows:

byte x = 0; byte y = 0;
active proctype toggle() {
    skip;
}

init {
end:
    (y == 1);
}

Makes the error go away:

~$ spin -a -search test.pml
(Spin Version 6.5.0 -- 17 July 2019)
...
State-vector 20 byte, depth reached 1, errors: 0
...

One should only ever use an end label when one is willing to guarantee that a process being stuck with no executable instruction is not a symptom of an undesired deadlock situation.

Patrick Trentin
  • 7,126
  • 3
  • 23
  • 40
  • Thank you for the explanation. It's clear now. My confusion was because I though that any process that hasn't reached it ending curly brace was going to be considered in an invalid end state. I didn't know that if the process was still executing something, even an infinite loop, it is not considered in an invalid end state. – tgonzalez89 Oct 18 '19 at 13:08
  • I was confused because the documentation states: "It is considered an invalid end-state error if a system can terminate in a state where not all active processes are either at the end of their code (i.e., at the closing curly brace of their proctype declarations) or at a local state that is marked with and end-state label." By this description my guess was that the toggle process would be in an invalid end state since it never reaches the closing curly brace or and end label. – tgonzalez89 Oct 18 '19 at 13:10
  • But is makes sense now because the toggle process it not at a state that is marked with and end label, the do loop still continues to run, it never blocks. – tgonzalez89 Oct 18 '19 at 13:12
  • @tgonzaleza Yeah, the catch is that in your original example the system does not really terminate, so the definition does not apply. – Patrick Trentin Oct 18 '19 at 13:33