我是Frama-C的新手,我想正确学习ACSL语法。我有这个虚拟的示例,Jessie插件无法验证第9和第12行。我缺少什么吗?要验证的函数(相等)将检查两个数组(a和b)在每个索引处是否具有相同的值:
/*@
requires \valid_range(a,0,n-1);
requires \valid_range(b,0,n-1);
requires n >= 0;
requires i >= 0 && i <= n;
assigns i;
behavior all_equal:
assumes i == n;
ensures \result == 1;
behavior some_not_equal:
assumes i != n;
ensures \result == 0;
*/
int equal(int a[], int n, int b[], int i) {
/*@
loop invariant 0 <= i <= n;
loop assigns i;
loop variant n-i;
*/
for (i = 0; i < n; i++) {
if (a[i] != b[i])
return 0;
}
return 1;
}
最佳答案
这里有一些不正确的地方:
behavior all_equal:
assumes i == n;
ensures \result == 1;
behavior some_not_equal:
assumes i != n;
ensures \result == 0;
在
assumes
子句中,所有变量均在函数的预状态下求值。这意味着,如果您有两个相等的大小为n
的数组,并假定i
为0
(不可能,请参见下一个说明),则i == n
将始终失败,除非该数组的大小为0
另一件事:您似乎将
i
用作循环控制的变量,在循环开始时将其设置为0,但是在注释中,您说在程序的预状态下i
是在0
和n
之间。这与我之前所说的结合在一起,是jessie无法证明这一点的原因之一。最后,您不能证明这一点的主要原因是因为您缺少一个基本的循环不变式,该循环不变式保证了当前迭代之前的所有数组索引的两个数组相等:
loop invariant loop invariant \forall integer k; 0 <= k < i ==> a[k] == b[k];
使用此不变式,您现在可以更好地指定您的行为。针对您的问题的正确解决方案是:
/*@
requires \valid_range(a,0,n-1);
requires \valid_range(b,0,n-1);
requires n >= 0;
behavior all_equal:
assumes \forall integer k; 0 <= k < n ==> a[k] == b[k];
ensures \result == 1;
behavior some_not_equal:
assumes \exists integer k; 0 <= k < n && a[k] != b[k];
ensures \result == 0;
*/
int equal(int a[], int n, int b[]) {
int i = 0;
/*@
loop invariant 0 <= i <= n;
loop invariant \forall integer k; 0 <= k < i ==> a[k] == b[k];
loop assigns i;
loop variant n-i;
*/
for (i = 0; i < n; i++) {
if (a[i] != b[i])
return 0;
}
return 1;
}