Почему бесконечный цикл не приводит к ошибке при проверке модели с помощью Promela и Spin?

Если я напишу следующий код в Promela и запущу его в Spin в режиме верификатора, он завершится с 0 ошибками. Он сообщает, что toogle и init не достигли состояния, но это, похоже, только предупреждения.

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

Меня это смутило, потому что я думал, что это даст мне ошибку «недопустимое конечное состояние». Если я изменю тело proctype toogle с помощью простого оператора skip, произойдет ошибка, как я и ожидал.

Почему это? Есть ли способ заставить симулятор сообщать о бесконечном цикле как об ошибке?

Что касается сообщений «unreached in proctype», добавление метки end к циклу do, похоже, ничего не дает.

Я запускаю spin 6.5.0 и выполняю следующие команды:

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

Это выходы, для справки.

С do циклом:

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

С 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

person tgonzaleza    schedule 17.10.2019    source источник


Ответы (1)


В этом примере

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

процесс init навсегда заблокирован (поскольку y == 1 всегда равен false), но процесс toggle всегда может выполнить что-то. Таким образом, нет недопустимой ошибки конечного состояния.

Вместо этого в этом примере

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

процесс init по-прежнему заблокирован навсегда, но процесс toggle может выполнить свою единственную инструкцию skip; и затем завершиться. На данный момент ни один из оставшихся процессов (то есть только init) не имеет инструкций, которые он может выполнить, поэтому Spin завершается с ошибкой invalid end state.

~$ 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
...

Есть ли способ заставить симулятор сообщать о бесконечном цикле как об ошибке?

Да. На самом деле есть несколько способов.

Самый простой подход — использовать опцию -l Spin:

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

С этой опцией Spin сообщает о любом бесконечном цикле, не содержащем никакого состояния, с прогресс.

Это результат вашей исходной проблемы:

~$ 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

Альтернативный подход заключается в использовании проверки модели LTL. Например, вы можете указать, что в какой-то момент число процессов (см. _nr_pr), находящихся в процессе выполнения, становится равным 0 (или больше, если вы допускаете некоторые бесконечные циклы), или проверьте правильность завершения конкретного процесса, используя удаленные ссылки.

Оба случая содержатся в следующем примере:

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) };

Оба первые

~$ 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

и второй

~$ 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 оказались ложными.


Что касается сообщений «unreached in proctype», добавление конечной метки в цикл do ничего не дает.

Метки end используются для удаления "недопустимого конечного состояния" ошибки, которая в противном случае была бы обнаружена.

Например, изменив предыдущий пример следующим образом:

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

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

Убирает ошибку:

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

Метку end следует использовать только тогда, когда готовы гарантировать, что процесс, зависший без исполняемой инструкции, не является признаком нежелательной тупиковой ситуации.

person Patrick Trentin    schedule 18.10.2019
comment
Спасибо за объяснение. Теперь ясно. Меня смутило то, что я думал, что любой процесс, который не достиг конечной фигурной скобки, будет считаться недопустимым конечным состоянием. Я не знал, что если процесс все еще что-то выполняет, даже бесконечный цикл, он не считается недопустимым конечным состоянием. - person tgonzaleza; 18.10.2019
comment
Я был сбит с толку, потому что в документации говорится: считается недопустимой ошибкой конечного состояния, если система может завершиться в состоянии, когда не все активные процессы находятся в конце своего кода (т. е. в закрывающей фигурной скобке их объявлений proctype ) или в локальном состоянии, отмеченном меткой и конечного состояния. Судя по этому описанию, я предположил, что процесс переключения будет в недопустимом конечном состоянии, поскольку он никогда не достигает закрывающей фигурной скобки или конечной метки. - person tgonzaleza; 18.10.2019
comment
Но теперь это имеет смысл, потому что переключатель обрабатывает его не в состоянии, отмеченном меткой и концом, цикл do все еще продолжает работать, он никогда не блокируется. - person tgonzaleza; 18.10.2019
comment
@tgonzaleza Да, загвоздка в том, что в вашем исходном примере система на самом деле не завершается, поэтому определение не применяется. - person Patrick Trentin; 18.10.2019