我试图用frama-c中的指针分配来证明while循环。不幸的是,我遇到了问题。如果使用for-loop和数组表示法重写测试代码,我设法证明了这一点。有没有人对如何证明这一点有任何想法?
我想证明的代码:
/*@
requires \valid(v+(0..n-1));
requires v != \null;
requires n > 0;
assigns v[0..n-1];
ensures \forall integer q; 0<=q<=n-1 ==> v[q]==(unsigned char)0;
*/
static void make_zero( unsigned char *v, size_t n ) {
volatile unsigned char *p = (unsigned char*)v;
/*@
loop invariant 0 <= n <= \at(n, Pre);
loop invariant \forall integer j; 0 <= j < (\at(n, Pre)-n) ==> \at(p, Pre)[j] == (unsigned char)0;
loop assigns n, p;
loop variant n; */
while( n-- ){
*p++ = 0;
}
}
重写代码:
/*@
loop invariant 0 <= i <= n;
loop invariant \forall integer j; 0 < j < i ==> p[j] == (unsigned char)0;
loop assigns i, p[0..n-1];
loop variant n-i;
*/
for(size_t i = 0; i<n; i++){
p[i] = 0;
}
答案 0 :(得分:3)
首先,一句话。 <{1}}前置条件v != \null
是多余的,可以删除。
另一个注释,\valid(v+(0..n-1))
是一个局部变量,它不在p
状态的范围内。因此Pre
或多或少没有意义(虽然被WP接受)。你可能意味着\at(p, Pre)
- 无论如何都更简单。
其次,你的循环分配是假的。 v
指向的数组的单元格也被修改。您必须将其更改为v
。
第三,你需要另一个循环不变量,它在assigns n, p, v[0..\at(n, Pre)-n-1]
和p
方面表达v
。否则,WP无法精确建模n
编写时会发生什么,并且无法证明修改后的*p
。这个不变量是loop assigns
。
你最后的问题是你声明p == v + (\at(n, Pre)-n)
不稳定。这里不需要这样做,实际上使得证明不可能:p
的值每次访问时都可能会改变。删除此限定符后,证明即告完成。
完整的参考代码:
p