1

根据手册页

进度标签用于定义正确性声明。进度标签规定了在任何无限系统执行中必须经常无限访问标记的全局状态的要求。验证者可以将任何违反此要求的行为报告为非进度循环。

Spin 有一个特殊的模式来证明不存在非进度循环。它使用预定义的 LTL 公式执行此操作:

(<>[] np_)

它将非进度正式化为标准的 Buchi 接受属性。

但是让我们看一下非常原始的promela规范

bool initialised = 0;

init{
progress:
    initialised++;
    assert(initialised == 1);
}

据我了解,assert应该保持但验证失败,因为initialised++只执行一次,而progress标签声称应该可以任意频繁地执行它。

然而,即使使用上面的 LTL 公式,这在 ispin 中也可以很好地验证(见下文)。

如何正确测试是否可以经常任意执行语句(例​​如锁定方案)?

(Spin 版本 6.4.7——2017 年 8 月 19 日)

               + Partial Order Reduction

完整的状态空间搜索:

never claim           + (:np_:)
assertion violations  + (if within scope of claim)
non-progress cycles   + (fairness disabled)
invalid end states    - (disabled by never claim)

状态向量 28 字节,深度达到 7,错误:0

   6 states, stored (8 visited)
   3 states, matched
   11 transitions (= visited+matched)
   0 atomic steps

哈希冲突:0(已解决)

内存使用统计(以兆字节为单位):

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

在初始化中未达到

   (0 of 3 states)

pan:经过时间 0.001 秒

未发现错误——您是否验证了所有声明?

更新

仍然不知道如何使用这个......

bool initialised = 0;

init{
    initialised = 1;
}

active [2] proctype reader()
{
assert(_pid >= 1);
(initialised == 1)
do
:: else ->
progress_reader:
    assert(true);
od
}

active [2] proctype writer()
{
assert(_pid >= 1);
(initialised == 1)
do
:: else -> 
    (initialised == 0)
progress_writer:
    assert(true);
od
}

让我们为非进展周期选择测试。然后 ispin 将其运行为

spin -a  test.pml
gcc -DMEMLIM=1024 -O2 -DXUSAFE -DNP -DNOCLAIM -w -o pan pan.c
./pan -m10000  -l

验证无误。

因此,让我们尝试使用 ltl 属性...

/*pid: 0 = init, 1-2 = reader, 3-4 =  writer*/

ltl progress_reader1{ []<> reader[1]@progress_reader }
ltl progress_reader2{ []<> reader[2]@progress_reader }
ltl progress_writer1{ []<> writer[3]@progress_writer }
ltl progress_writer2{ []<> writer[4]@progress_writer }

bool initialised = 0;



init{
    initialised = 1;
}

active [2] proctype reader()
{
assert(_pid >= 1);
(initialised == 1)
do
:: else ->
progress_reader:
    assert(true);
od
}

active [2] proctype writer()
{
assert(_pid >= 1);
(initialised == 1)
do
:: else -> 
    (initialised == 0)
progress_writer:
    assert(true);
od
}

现在,首先,

  the model contains 4 never claims: progress_writer2, progress_writer1, progress_reader2, progress_reader1
  only one claim is used in a verification run
  choose which one with ./pan -a -N name (defaults to -N progress_reader1)
  or use e.g.: spin -search -ltl progress_reader1 test.pml

好吧,我不在乎,我只想让它最终运行,所以让我们继续progress_writer1担心以后如何将它们拼接在一起:

/*pid: 0 = init, 1-2 = reader, 3-4 =  writer*/
/*ltl progress_reader1{ []<> reader[1]@progress_reader }*/
/*ltl progress_reader2{ []<> reader[2]@progress_reader }*/
ltl progress_writer1{ []<> writer[3]@progress_writer }
/*ltl progress_writer2{ []<> writer[4]@progress_writer }*/
bool initialised = 0;
init{
    initialised = 1;
}
active [2] proctype reader()
{
assert(_pid >= 1);
(initialised == 1)
do
:: else ->
progress_reader:
    assert(true);
od
}
active [2] proctype writer()
{
assert(_pid >= 1);
(initialised == 1)
do
:: else -> 
    (initialised == 0)
progress_writer:
    assert(true);
od
}

ispin 运行这个

spin -a  test.pml
ltl progress_writer1: [] (<> ((writer[3]@progress_writer)))
gcc -DMEMLIM=1024 -O2 -DXUSAFE -DSAFETY -DNOCLAIM -w -o pan pan.c
./pan -m10000 

这不会产生错误,而是报告

unreached in claim progress_writer1
    _spin_nvr.tmp:3, state 5, "(!((writer[3]._p==progress_writer)))"
    _spin_nvr.tmp:3, state 5, "(1)"
    _spin_nvr.tmp:8, state 10, "(!((writer[3]._p==progress_writer)))"
    _spin_nvr.tmp:10, state 13, "-end-"
    (3 of 13 states)    

是的?灿烂!我完全不知道该怎么做。

我如何让它运行?

4

2 回答 2

2

您的代码示例的问题是它没有任何无限系统执行。

进度标签用于定义正确性声明。进度标签规定了在任何无限系统执行中必须经常无限访问标记的全局状态的要求。验证者可以将任何违反此要求的行为报告为非进度循环。


试试这个例子:

short val = 0;

init {
    do
        :: val == 0 ->
           val = 1;
           // ...
           val = 0;

        :: else ->
progress:
           // super-important progress state
           printf("progress-state\n");
           assert(val != 0);
    od;
};

正常检查没有发现任何错误:

~$ spin -search test.pml 

(Spin Version 6.4.3 -- 16 December 2014)
    + Partial Order Reduction

Full statespace search for:
    never claim             - (none specified)
    assertion violations    +
    cycle checks            - (disabled by -DSAFETY)
    invalid end states      +

State-vector 12 byte, depth reached 2, errors: 0
        3 states, stored
        1 states, matched
        4 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
  128.000   memory used for hash table (-w24)
    0.534   memory used for DFS stack (-m10000)
  128.730   total actual memory usage


unreached in init
    test.pml:12, state 5, "printf('progress-state\n')"
    test.pml:13, state 6, "assert((val!=0))"
    test.pml:15, state 10, "-end-"
    (3 of 10 states)

pan: elapsed time 0 seconds

而检查进度会产生错误:

~$ spin -search -l test.pml 

pan:1: non-progress cycle (at depth 2)
pan: wrote test.pml.trail

(Spin Version 6.4.3 -- 16 December 2014)
Warning: Search not completed
    + Partial Order Reduction

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

State-vector 20 byte, depth reached 7, errors: 1
        4 states, stored
        0 states, matched
        4 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
  128.000   memory used for hash table (-w24)
    0.534   memory used for DFS stack (-m10000)
  128.730   total actual memory usage



pan: elapsed time 0 seconds

WARNING : 确保写-l在 option 之后-search,否则不会交给验证者。


你问:

如何正确测试是否可以经常任意执行语句(例​​如锁定方案)?

简单地写一个活性属性:

ltl prop { [] <> proc[0]@label };

这将检查具有 nameproc和 pid的进程是否0经常无限执行与label.

于 2017-11-02T10:17:43.560 回答
1

由于您的编辑大大改变了问题,我写了一个新的答案以避免混淆。此答案针对新内容。下一次,考虑创建一个新的、单独的问题。


这是注意unreached in ...警告消息非常重要的情况之一,因为它会影响验证过程的结果。

警告信息:

unreached in claim progress_writer1
    _spin_nvr.tmp:3, state 5, "(!((writer[3]._p==progress_writer)))"
    _spin_nvr.tmp:3, state 5, "(1)"
    _spin_nvr.tmp:8, state 10, "(!((writer[3]._p==progress_writer)))"
    _spin_nvr.tmp:10, state 13, "-end-"
    (3 of 13 states)   

_spin_nvr.tmp与编译过程中创建的文件内容有关:

...
never progress_writer1 {    /* !([] (<> ((writer[3]@progress_writer)))) */
T0_init:
    do
    :: (! (((writer[3]@progress_writer)))) -> goto accept_S4    // state 5
    :: (1) -> goto T0_init
    od;
accept_S4:
    do
    :: (! (((writer[3]@progress_writer)))) -> goto accept_S4    // state 10
    od;
}                                                               // state 13 '-end-'
...

粗略地说,您可以将此视为Buchi Automaton的规范,它接受您的writer流程执行_pid等于3,其中它不会progress_writer无限频繁地到达带有标签的语句,即它只执行有限次数

要理解这一点,您应该知道,为了验证一个ltl属性φspin构建一个自动机,其中包含原始Promela模型中不满足的所有路径φ。这是通过计算对原始系统建模的自动机的同步乘积φ来完成的,该自动机表示您要验证的属性的否定。在您的示例中,否定φ是由上面的代码摘录给出的,_spin_nvr.tmp并标有never progress_writer1. 然后,Spin检查是否有任何可能执行此自动机:

  • 如果有,则φ侵犯了财产,并且这种执行痕迹是您财产的见证人(又名反例)
  • 否则,φ验证属性。

警告告诉您,在生成的同步产品中,这些状态都无法到达。为什么会这样?

考虑一下:

   active [2] proctype writer()
   {
1:     assert(_pid >= 1);
2:     (initialised == 1)
3:     do
4:         :: else ->
5:             (initialised == 0);
6: progress_writer:
7:             assert(true);
8:     od
   }

在线2:时,您检查一下initialised == 1。此语句强制writer在 line 处阻塞,2:直到 wheninitialised设置为1。幸运的是,这是由init流程完成的。

在线5:时,您检查一下initialised == 0。此语句强制writer在 line 处阻塞,5:直到 wheninitialised设置为0。但是,没有任何进程会设置initialised0代码中的任何位置。因此,标记为的代码行progress_writer:实际上是无法访问的。

请参阅文档

(1)       /* always executable               */
(0)       /* never executable                */
skip      /* always executable, same as (1)  */
true      /* always executable, same as skip */
false     /* always blocks, same as (0)      */
a == b    /* executable only when a equals b */

条件语句只有在成立时才能执行(通过)。[...]

于 2017-11-02T12:45:50.503 回答