关于strstr的ACSL合同

关于strstr的ACSL合同,c,string,strstr,frama-c,C,String,Strstr,Frama C,我试图为一个C函数编写一个规范,该函数搜索另一个字符串中第一个出现的字符串(实际上是string.h的strstr函数) 我遇到的第一个问题是,我无法证明循环不变量,我认为我使用strlen(在u fc_string_axiomatic.h中定义的公理)的方式有问题 #包括 /*@ 需要有效的_字符串(s1); 需要有效的_字符串(s2); */ 字符*strfind(常量字符*s1,常量字符*s2){ 如果(*s2==0) 返回s1; /*@ 循环不变量0你的循环不变量是正确的(我成功地证

我试图为一个C函数编写一个规范,该函数搜索另一个字符串中第一个出现的字符串(实际上是string.h的strstr函数)

我遇到的第一个问题是,我无法证明循环不变量,我认为我使用strlen(在u fc_string_axiomatic.h中定义的公理)的方式有问题

#包括
/*@ 
需要有效的_字符串(s1);
需要有效的_字符串(s2);
*/
字符*strfind(常量字符*s1,常量字符*s2){
如果(*s2==0)
返回s1;
/*@ 

循环不变量0你的循环不变量是正确的(我成功地证明了它们),但是它们太弱了,你应该加强它们。下面是我用Frama-C插件(Jessie的继任者)证明的函数的一个版本

/*@ 
    requires valid_string(s1);
    requires valid_string(s2);
*/
char *strfind (const char *s1, const char *s2) {
  if (*s2 == 0) 
      return s1;
  /*@ 
    loop invariant valid_string(s1);
    loop invariant strlen(\at(s1,Pre)) == (s1 - \at(s1,Pre)) + strlen(s1);
    loop invariant 0 <= s1 - \at(s1,Pre) <= strlen(\at(s1,Pre));
    loop assigns s1;
  */
  while (*s1) { 
    const char *rs1 = s1;
    const char *rs2 = s2;
    /*@ 
        loop invariant valid_string(rs1);
        loop invariant valid_string(rs2);
        loop invariant strlen(\at(s1,Pre)) == (rs1 - \at(s1,Pre)) + strlen(rs1);
        loop invariant strlen(s2) == (rs2 - s2) + strlen(rs2);
        loop invariant 0 <= rs1 - s1 <= strlen(s1);
        loop invariant 0 <= rs2 - s2 <= strlen(s2);
        loop assigns rs1, rs2;
    */
    while (*rs1 && *rs2 && (*rs1 == *rs2)) { 
        rs1++; 
        rs2++; 
    }
    if (*rs2 == 0) 
        return s1;
    s1++;
  }
  return 0;
}
/*@
需要有效的_字符串(s1);
需要有效的_字符串(s2);
*/
字符*strfind(常量字符*s1,常量字符*s2){
如果(*s2==0)
返回s1;
/*@ 
循环不变有效_字符串(s1);
循环不变strlen(\at(s1,Pre))==(s1-\at(s1,Pre))+strlen(s1);

循环不变量0侧注:代码简化:while((*rs1==*rs2)和&*rs1){。谢谢!如果我想指定两种行为(找到/未找到),我可以简单地检查(在假设子句中)在执行期间是否!*s1(即主循环到达末尾,因为没有找到模式)?否。
假设在函数的预状态下对
子句进行求值,并且不能引用函数体内发生的情况。成功案例必须使用存在量化,失败案例必须使用forall/exists。要完成byako的注释(但如果您在行为方面有具体问题,您应该提出另一个问题),如果您有行为,您可以使用
for bhv:assert…;
指示仅当
bhv
处于活动状态时,断言才应保持。在您的情况下,主循环后的
for found:assert\false
将指示当处于行为
中时已找到
(如图所示,必须在pre状态上使用假设子句进行精确计算),函数不应达到
返回0;
/*@ 
    requires valid_string(s1);
    requires valid_string(s2);
*/
char *strfind (const char *s1, const char *s2) {
  if (*s2 == 0) 
      return s1;
  /*@ 
    loop invariant valid_string(s1);
    loop invariant strlen(\at(s1,Pre)) == (s1 - \at(s1,Pre)) + strlen(s1);
    loop invariant 0 <= s1 - \at(s1,Pre) <= strlen(\at(s1,Pre));
    loop assigns s1;
  */
  while (*s1) { 
    const char *rs1 = s1;
    const char *rs2 = s2;
    /*@ 
        loop invariant valid_string(rs1);
        loop invariant valid_string(rs2);
        loop invariant strlen(\at(s1,Pre)) == (rs1 - \at(s1,Pre)) + strlen(rs1);
        loop invariant strlen(s2) == (rs2 - s2) + strlen(rs2);
        loop invariant 0 <= rs1 - s1 <= strlen(s1);
        loop invariant 0 <= rs2 - s2 <= strlen(s2);
        loop assigns rs1, rs2;
    */
    while (*rs1 && *rs2 && (*rs1 == *rs2)) { 
        rs1++; 
        rs2++; 
    }
    if (*rs2 == 0) 
        return s1;
    s1++;
  }
  return 0;
}