当我尝试使用默认逻辑标签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,但也许我没有为每次小更新升级答案 0 :(得分:4)
LoopCurrent
和LoopEntry
。这已在开发版本中修复(请参阅http://bts.frama-c.com/view.php?id=1353),并应出现在下一版本中。
关于其他预定义标签,
Pre
始终引用函数开头的状态。Old
只能在合同中使用,并且指的是此合同的前置状态(即评估requires
和assumes
子句的状态)。因此,对于函数契约,它等效于Pre
,但对于语句契约,不等于(除非您签订了包含函数主块的契约)。Here
表示评估相应注释的程序点。在合同中,其含义取决于它出现的条款。Post
只能在ensures
,assigns
,allocates
或frees
条款中使用,并且可以参考合同末尾的州。