Coq VST中使用异构阵列验证程序

Coq VST中使用异构阵列验证程序,coq,verifiable-c,Coq,Verifiable C,我正在验证一个使用数组存储异构数据的c程序——特别是,该程序使用数组实现cons单元格,其中数组的第一个元素是整数值,第二个元素是指向下一个cons单元格的指针 例如,此列表的自由操作为: void listfree(void * x) { if((x == 0)) { return; } else { void * n = *((void **)x + 1); listfree(n); free(x); return; } } 注意:此处未

我正在验证一个使用数组存储异构数据的c程序——特别是,该程序使用数组实现cons单元格,其中数组的第一个元素是整数值,第二个元素是指向下一个cons单元格的指针

例如,此列表的自由操作为:

void listfree(void * x) {
  if((x == 0)) {
    return;
  } else {
    void * n = *((void **)x + 1);
    listfree(n);
    free(x);
    return;
  }
}
注意:此处未显示,但其他代码部分将读取数组的值并将其视为整数

虽然我知道表达它的自然方式是某种结构,但程序本身是使用数组编写的,我不能改变这一点

我应该如何在VST中指定内存的结构

我定义了一个
lseg
谓词,如下所示:

Fixpoint lseg (x: val) (s: (list val)) (self_card: lseg_card) : mpred := match self_card with
    | lseg_card_0  =>  !!(x = nullval) && !!(s = []) && emp
    | lseg_card_1 _alpha_513 => 
      EX v : Z,
      EX s1 : (list val),
      EX nxt : val,
 !!(~ (x = nullval)) && 
   !!(s = ([(Vint (Int.repr v))] ++ s1)) && 
   (data_at Tsh (tarray tint 2) [(Vint (Int.repr v)); nxt] x) * 
   (lseg nxt s1 _alpha_513)
end.

然而,我在尝试计算
void*n=*(void**)x时遇到了麻烦大概是因为该规范声明内存包含一个int数组,而不是指针。

问题可能如下所示,几乎可以按如下所示解决

C语义允许将整数(大小合适的)强制转换为指针,反之亦然,只要您不实际对整数值执行任何指针操作,反之亦然。很可能您的C程序遵守这些规则。但是可验证C的类型系统试图强制整数类型的局部变量(和数组元素等)永远不包含指针值,反之亦然(特殊的整数值0除外,它是NULL)

然而,可验证C确实支持(经证明基本上是合理的)解决方案,以实现更严格的强制执行:

typedef void  * int_or_ptr
 #ifdef COMPCERT
   __attribute((aligned(_Alignof(void*))))
 #endif
  ;
也就是说,
int\u或\u ptr
类型是
void*
,但具有属性“将其作为
void*
对齐”。因此,它在语义上与
void*
相同,但冗余属性提示VST类型系统减少对C类型强制的限制

所以,当我说“几乎可以解决”时,我是在问:你能修改C程序使用一个数组“void*对齐为void*”

如果是,那么您可以继续。您的VST验证应该使用
int\u或
,这是VST Floyd提供的type
Ctypes.type
的定义,当引用这些数组元素或这些元素加载到的局部变量的C语言类型时

不幸的是,参考手册(VC.pdf)中没有记录int_或ptr_类型,这是一个应该正确的遗漏。您可以查看progs/int_或_ptr.c和progs/verif_int_或_ptr.v,但它们所做的远远超出了您的需要:它们将区分奇数整数和对齐指针的运算符公理化,这在C11中是未定义的(但与C11一致,否则ocaml垃圾收集器将永远无法工作)。也就是说,这些公理化的外部函数与CompCert、gcc、clang一致;但您不需要它们中的任何一个,因为您在int_或_指针上执行的唯一操作是完全合法的“与NULL比较”和“转换为整数”或“转换为
struct foo*