You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求解决Frama-C AstraVer验证C循环排序函数的剩余Safety与Behavior验证目标问题

请求解决Frama-C AstraVer验证C循环排序函数的剩余Safety与Behavior验证目标问题

我目前正在对C语言实现的循环排序函数做全代码验证,用ACSL注解配合Frama-C的AstraVer后端,在Why3 GUI里查看验证结果,现在还差几个目标没完成:

  • Safety部分:67/68,还差一个「loop variant decrease」目标未证明
  • Behavior部分:32/39,还有多个目标待完成

以下是各部分的验证结果截图:

  • Safety部分:
    safety section
  • Behavior第一部分:
    behavior section 1
  • Behavior第二部分:
    behavior section 2

这是我当前的循环排序代码(带ACSL注解):

/*@ predicate sorted(int *array, integer first, integer last) =
   @    \forall integer i;
   @        first < i < last ==> array[i - 1] <= array[i];
*/

/*@
  @ requires array != \null; 
  @ requires \valid(array + (0 .. size-1));
  @ requires size >= 0; 
  @ assigns array[0..size-1]; 
  @
  @ ensures \forall integer i; 0 <= i < size ==> array[i] >= \old(array[i]);
  @ ensures sorted(array, 0, size);
  */
void sorting(int *array, int size) {
    int bound, idx, x, i, tmp;

    /*@ loop invariant 0 <= bound <= size - 2; 
      @ loop variant size - bound;    
      @*/
    for (bound = 0; bound <= size - 2; bound++) {
        /* @assert bound < size; */ 
        x = array[bound];
        idx = bound;

        /*@ loop invariant bound + 1 <= i <= size;
          @ loop invariant idx >= bound;                           
          @ loop invariant idx <= size-1;                          
          @ loop assigns i, idx;
          @ loop variant size - i;   
          @*/
        for (i = bound + 1; i < size; i++) {
            /*@ assert i < size; @*/
              
            if (array[i] < x) {
                /*@ assert idx + 1 < size; @*/
                idx++;
            }
        }

        if (idx == bound) {
            continue;
        }

        
        /*@ loop invariant idx >= bound && idx < size; 
          @ loop assigns idx;
          @ loop variant size - idx;
        @ */
        while (x == array[idx]) {
            /*@ assert bound <= idx < size; */ 
            idx += 1;
            /*@ assert idx < size; */
        }

        if (idx != bound) {
            /*@ assert idx < size; */
            tmp = array[idx];
            array[idx] = x;
            x = tmp;
        }
    
    /*@
      @ loop invariant bound <= idx < size;
      @ loop assigns idx, tmp, x, i, array[bound .. size-1];
      @ loop variant idx - bound;
    @ */
    
        while (idx != bound) {
            /*@ assert bound <= idx < size;  */
            idx = bound;

            /*@ loop invariant bound < i <= size;     
              @ loop invariant idx >= bound;
              @ loop invariant idx <= size-1;
              @ loop assigns i, idx; 
              @ loop variant size - i;         
             @*/
            for (i = bound + 1; i < size; i++) {
                if (array[i] < x) {
                    /*@ assert idx + 1 < size; */
                    idx += 1;
                }
            }
         
            /*@ assert idx < size; */
            /*@ 
              @ loop invariant idx >= bound && idx < size;
              @ loop assigns idx;
              @ loop variant size - idx;  
              @ */
            while (x == array[idx]) {
                /*@ assert idx + 1 < size; */
                idx += 1;
                /*@ assert idx < size;  */
            }
            /* @assert idx < size; */
            if (x != array[idx]) {
                /* @assert idx < size; */
                tmp = array[idx];
                /* @assert idx < size; */
                array[idx] = x;
                x = tmp;
            }
        }
    }
}

我还尝试过定义置换相关的公理,代码如下,但验证效果没提升,而且我觉得用公理有点像“作弊”,不太想用这种方式:

/*@ axiomatic Permut {
  @ predicate permut{L1,L2}(int *t1, int *t2, integer n);
  @     axiom permut_refl{L}:
  @         \forall int *t, integer n; permut{L,L}(t,t,n);
  @     axiom permut_sym{L1,L2}:
  @         \forall int *t1, *t2, integer n;
  @             permut{L1,L2}(t1,t2,n) ==> permut{L2,L1}(t2,t1,n);
  @     axiom permut_trans{L1,L2,L3}:
  @         \forall int *t1, *t2, *t3, integer n;
  @             permut{L1,L2}(t1,t2,n) && permut{L2,L3}(t2,t3,n)
  @             ==> permut{L1,L3}(t1,t3,n);
  @     axiom permut_exchange{L1,L2}:
  @         \forall int *t1, *t2, integer i, j, n;
  @         swap{L1, L2}(t1, t2, i, j, n) ==> permut{L1,L2}(t1,t2,n);
  @ }
  @*/

我感觉ACSL引理可能是解决问题的关键,但自己想不出有效的引理来补充。有没有大佬能给点建议,我该加哪些注解或者调整现有注解,才能完成剩余的验证目标?

备注:内容来源于stack exchange,提问作者st_dec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 10:09:32