strstr

时间:2015-08-07 15:19:50

标签: c string strstr frama-c

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

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

#include<string.h>
/*@ 
    requires valid_string(s1);
    requires valid_string(s2);

*/
char *strfind (const char *s1, const char *s2) {
  if (*s2 == 0) 
      return s1;
  /*@ 
    loop invariant 0 <= s1 - \at(s1,Pre) <= strlen(\at(s1,Pre));
  */
  while (*s1) { 
    const char *rs1 = s1;
    const char *rs2 = s2;
    /*@ 
        loop invariant 0 <= rs1 - s1 <= strlen(s1);
        loop invariant 0 <= rs2 - s2 <= strlen(s2);
    */
    while (*rs1 && *rs2 && (*rs1 == *rs2)) { 
        rs1++; 
        rs2++; 
    }
    if (*rs2 == 0) 
        return s1;
    s1++;
  }
  return 0;
}

1 个答案:

答案 0 :(得分:2)

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

/*@ 
    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;
}

首先,请注意valid_string上添加的循环不变量。如果没有它们,那么strlen(s1/rs1/rs2)仍然是正数的证明器是不明确的,因为指针可能在字符串结束后增加了。

接下来,我添加了相关的例如\at(s1,Pre)s1及其各自的长度。这些比你的不等式的正确部分更强,并用来证明所说的不等式 - 使用假设valid_string(s1),确保strlen(s1)>=0

你的不等式的左边部分是正确的循环不变量,并且最初可以证明(没有任何额外的不变量)。

请记住,对于所有K,第一个K循环不变量必须是归纳。这意味着,根据它们在迭代i处保持的假设,您应该能够证明它们在迭代i+1处保持不变。因此,您可能需要编写比您想要证明的更强的不变量(因为那些可能不是归纳的)。