当我尝试使用默认逻辑标签LoopEntry和LoopCurrent时,我遇到了一些麻烦 . 这是一个简单的例子,我使用的不同证明器(alt-ergo,coq,cvc3,z3)无法证明:
/*@ requires n > 0;*/
void f(int n){
int i = 0;
/*@ loop invariant \at(i,LoopEntry) == 0;
@ loop invariant \at(i,LoopCurrent) >= \at(i,LoopEntry);
@ loop invariant 0 <= i <= n;
@ loop assigns i;
@ loop variant n-i;
*/
while(i < n){
i++;
}
}
特别是,没有证明第一和第二不变量(其他不存在问题) . 现在,如果我通过在i的声明/定义之后添加标签“label”来修改这个简单的例子,并且如果我引用该标签,并通过Here更改LoopCurrent(这给出了这个片段:
/*@ requires n > 0;*/
void f(int n){
int i = 0;
label : ;
/*@ loop assigns i;
@ loop invariant \at(i,label) == 0;
@ loop invariant \at(i,Here) >= \at(i,label);
@ loop invariant 0 <= i <= n;
@ loop variant n-i;
*/
while(i < n){
i++;
}
}
)
现在一切都证明了 .
我发现有关Acsl默认逻辑标签的文档很容易理解,我期望第一个例子被证明是第二个 . 你能解释一下问题出在哪里吗?
袋鼠
PS1:在循环子句中使用Pre时会引用什么?第一次循环迭代或前一次迭代之前的状态??
PS2:我正在使用Frama-C Fluorine,但也许我没有为每次小更新升级
1 回答
在Fluorine的WP中确实不支持
LoopCurrent
和LoopEntry
. 这在开发版本中已修复(请参阅http://bts.frama-c.com/view.php?id=1353),并应出现在下一版本中 .关于其他预定义标签,
Pre
始终指的是函数开头的状态 .Old
只能在 Contract 中使用,并且指的是本 Contract 的前置状态(即评估requires
和assumes
子句的状态) . 因此,对于函数 Contract ,它等效于Pre
,但对于语句 Contract 则不等同(除非您签订了包含函数主块的合约) .Here
表示评估相应注释的程序点 . 在 Contract 中,其含义取决于它出现的条款 .Post
只能在ensures
,assigns
,allocates
或frees
子句中使用,并且可以参考 Contract 末尾的状态 .