我是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的数组,并假定i0(不可能,请参见下一个说明),则i == n将始终失败,除非该数组的大小为0

另一件事:您似乎将i用作循环控制的变量,在循环开始时将其设置为0,但是在注释中,您说在程序的预状态下i是在0n之间。这与我之前所说的结合在一起,是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;
}

10-04 16:36