正确使用``progress``标签

时间:2017-11-02 08:12:56

标签: concurrency formal-verification model-checking promela spin

根据the man pages

  

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

  

Spin有一种特殊的模式来证明没有非进展周期。它使用预定义的LTL公式:

(<>[] np_)
     

将非进展正式化为标准的Buchi接受财产。

但是,让我们来看看非常原始的promela规范

bool initialised = 0;

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

根据我的理解,assert应该成立,但验证失败,因为initialised++只执行一次而progress标签声称应该可以经常执行它。

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

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

  

(Spin Version 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
     

在init

中未获得
   (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)    

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

如何让它运行?

2 个答案:

答案 0 :(得分:1)

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

  

进度标签用于定义正确性声明。进步   label表示标记的全局状态必须是的要求   在任何无限的系统执行中经常无限地访问 。任何   验证者可以将违反此要求的行为报告为   非进展周期。

请尝试使用此示例:

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

警告:确保在选项-l之后写-search,否则不会将其移交给验证者。

你问:

  

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

简单地写一个活跃的财产:

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

这会检查名为proc且pid 0的流程是否经常执行与label对应的语句。

答案 1 :(得分:0)

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

这是注意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的声明,即 ie它只有有限次数

为了理解这一点,您应该知道,要验证φ属性spinPromela会构建一个自动机,其中包含原始φ模型中不满足的所有路径φ。这是通过计算自动机的同步产品来完成的,该自动机使用表示要验证的属性φ的否定的自动机对原始系统进行建模。 在您的示例中,_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。在2:设置为initialised之前,此语句强制1阻止init行。幸运的是,这是由5:进程完成的。

在第initialised == 0行,您检查writer。在5:设置为initialised之前,此语句强制0阻止initialised行。但是,没有任何进程会在代码中的任何位置将0设置为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 */ 的代码行实际上无法访问。

请参阅documentation

<SELECT name="toAddress">
   <option value="info">Info</option>
   <option value="general">General</option>
</SELECT>
     

如果条件语句成立,则只能执行(传递)。 [...]