Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 我们写“好吗?”;断言;在每次函数调用之后,何时调用一系列函数?_C_Frama C_Acsl - Fatal编程技术网

C 我们写“好吗?”;断言;在每次函数调用之后,何时调用一系列函数?

C 我们写“好吗?”;断言;在每次函数调用之后,何时调用一系列函数?,c,frama-c,acsl,C,Frama C,Acsl,让我从这个例子开始提问: void A (void) { B(); C(); D(); E(); ... // function calls go on. return; } 现在,让我们向代码中添加ACSL注释: /*@ ensures PostConditionOfB(); ensures PostConditionOfC(); ensures PostConditionOfD(); ensures PostConditionOfE();

让我从这个例子开始提问:

void A (void)
{
  B();
  C();
  D();
  E();
  ... // function calls go on.

  return;
}
现在,让我们向代码中添加ACSL注释:

/*@
   ensures PostConditionOfB();
   ensures PostConditionOfC();
   ensures PostConditionOfD();
   ensures PostConditionOfE();
   ... // ensuring the predicates of the remaining functions goes on.
*/
void A (void)
{
  B();
  C();
  D();
  E();
  ... // function calls go on.

  return;
}
/*@
   ensures PostConditionOfB();
   ensures PostConditionOfC();
   ensures PostConditionOfD();
   ensures PostConditionOfE();
   ... // ensuring the predicates of the remaining functions goes on.
*/
void A (void)
{
  B();
  //@ assert PostConditionOfB();
  C();
  //@ assert PostConditionOfB();
  //@ assert PostConditionOfC();
  D();
  //@ assert PostConditionOfB();
  //@ assert PostConditionOfC();
  //@ assert PostConditionOfD();
  E();
  //@ assert PostConditionOfB();
  //@ assert PostConditionOfC();
  //@ assert PostConditionOfD();
  //@ assert PostConditionOfE();
  ... // function calls go on.

  return;
} 
我让Frama-C通过执行“Frama-C-gui-wp file.C”来检查代码。当在函数A中调用函数B、C和D时,合同被标记为有效。通过添加函数E的调用以及可能更多的其他函数,合同被标记为无效。我们提出了在每个函数调用之后添加“assert”的想法,以便为Frama-C提供假设满足哪些后条件的线索。通过这种方法,合同被标记为有效。查看代码:

/*@
   ensures PostConditionOfB();
   ensures PostConditionOfC();
   ensures PostConditionOfD();
   ensures PostConditionOfE();
   ... // ensuring the predicates of the remaining functions goes on.
*/
void A (void)
{
  B();
  C();
  D();
  E();
  ... // function calls go on.

  return;
}
/*@
   ensures PostConditionOfB();
   ensures PostConditionOfC();
   ensures PostConditionOfD();
   ensures PostConditionOfE();
   ... // ensuring the predicates of the remaining functions goes on.
*/
void A (void)
{
  B();
  //@ assert PostConditionOfB();
  C();
  //@ assert PostConditionOfB();
  //@ assert PostConditionOfC();
  D();
  //@ assert PostConditionOfB();
  //@ assert PostConditionOfC();
  //@ assert PostConditionOfD();
  E();
  //@ assert PostConditionOfB();
  //@ assert PostConditionOfC();
  //@ assert PostConditionOfD();
  //@ assert PostConditionOfE();
  ... // function calls go on.

  return;
} 
问题是:有没有更好的方法来检查包含多个函数调用的函数的契约,而不是在每个函数调用之后添加“assert”

更新代码:

文件.h如下所示:

#define SIZE_FIRST 100
#define SIZE_SECOND 30
#define SIZE_THIRD 30

typedef struct
{
int  Field_5;
int  Field_6;
} Struct_C;

typedef struct
{
int Field_1;
int Field_2;
int Field_3;
int Field_4;
Struct_C At_1 [ SIZE_SECOND ];
Struct_C At_2 [ SIZE_THIRD ];
Struct_C At_3 [ SIZE_THIRD ];
} Struct_B;

typedef struct
{
 Struct_B At [ SIZE_FIRST ];
 int Count;
} Struct_A;

/*@ predicate
  Reset_Basics (Struct_B * Stct_B) =
   (Stct_B->Field_1 == 0) &&
   (Stct_B->Field_2 == 0) &&
   (Stct_B->Field_3 == 0) &&
   (Stct_B->Field_4 == 0);
*/

/*@ predicate 
  Reset_At_1 (Struct_B * Stct_B, integer First, integer Last) =
    \forall integer Index; First <= Index < Last ==>
                (Stct_B->At_1 [ Index ].Field_5 == 0) &&
                (Stct_B->At_1 [ Index ].Field_6 == 0);
*/


/*@ predicate 
  Reset_At_2 (Struct_B * Stct_B, integer First, integer Last) =
    \forall integer Index; First <= Index < Last ==>
                (Stct_B->At_2 [ Index ].Field_5 == 0) &&
                (Stct_B->At_2 [ Index ].Field_6 == 0);
*/

/*@ predicate 
  Reset_At_3 (Struct_B * Stct_B, integer First, integer Last) =
    \forall integer Index; First <= Index < Last ==>
                (Stct_B->At_3 [ Index ].Field_5 == 0) &&
                (Stct_B->At_3 [ Index ].Field_6 == 0);
*/
#先定义尺寸"100
#定义大小_秒30
#定义第三个30的大小
类型定义结构
{
int字段_5;
int字段_6;
}结构;
类型定义结构
{
int字段_1;
int字段_2;
int字段_3;
int字段_4;
结构C在1[大小秒];
结构C位于2[尺寸三分之一];
3号结构[SIZE_THIRD];
}结构;
类型定义结构
{
结构B位于[尺寸第一];
整数计数;
}结构A;
/*@谓词
重置基础(结构*Stct)=
(Stct_B->字段_1==0)&&
(Stct_B->字段_2==0)&&
(Stct_B->字段_3==0)&&
(Stct_B->字段_4==0);
*/
/*@谓词
在_1处重置_(结构B*Stct_B,先整型,后整型)=
\所有整数指数;弗斯特
(Stct_B->At_1[索引]。字段_5==0)&&
(Stct_B->At_1[索引]。字段_6==0);
*/
/*@谓词
在_2重置_(结构B*Stct_B,先整型,后整型)=
\所有整数指数;弗斯特
(Stct_B->At_2[索引]。字段_5==0)&&
(Stct_B->At_2[索引]。字段_6==0);
*/
/*@谓词
在3处重置(结构B*Stct B,先整型,后整型)=
\所有整数指数;弗斯特
(Stct_B->At_3[索引]。字段_5==0)&&
(Stct_B->At_3[索引]。字段_6==0);
*/
文件.c如下所示:

#include "file.h"

void Initialize (Struct_A * const Stct_A);
void Reset (Struct_B * const Stct_B);
void Reset_Basics (Struct_B * const Stct_B);
void Reset_At_1 (Struct_B * const Stct_B);
void Reset_At_2 (Struct_B * const Stct_B);
void Reset_At_3 (Struct_B * const Stct_B);

/*@ 
   assigns Stct_A->At [ 0..(SIZE_FIRST - 1) ];
   assigns Stct_A->Count;
*/
void Initialize (Struct_A * const Stct_A)
{

/*@
 loop invariant 0 <= Index <= SIZE_FIRST;

 loop invariant \forall integer Stct_B_Index; (0 <= Stct_B_Index < 
      Index) ==> Reset_Basics(&(Stct_A->At [ Stct_B_Index ]));

 loop invariant \forall integer Stct_B_Index; (0 <= Stct_B_Index < 
      Index) ==> Reset_At_1(&(Stct_A->At [ Stct_B_Index ]), 0,   
      SIZE_SECOND);

 loop invariant \forall integer Stct_B_Index; (0 <= Stct_B_Index < 
      Index) ==> Reset_At_2(&(Stct_A->At [ Stct_B_Index ]), 0, 
      SIZE_THIRD);

 loop invariant \forall integer Stct_B_Index; (0 <= Stct_B_Index < 
      Index) ==> Reset_At_3(&(Stct_A->At [ Stct_B_Index ]), 0,
      SIZE_THIRD);

 loop assigns Index, Stct_A->At [ 0..(SIZE_FIRST - 1) ];

 loop variant SIZE_FIRST - Index;
*/
 for (int Index = 0; Index < SIZE_FIRST; ++(Index))
  {
   Reset(&(Stct_A->At [ Index ]));
  } 

  Stct_A->Count = 0;

 return;
 }

/*@ 
  assigns * Stct_B;
  ensures Reset_Basics(Stct_B);
*/
void Reset_Basics (Struct_B * const Stct_B) 
{

  Stct_B->Field_1 = 0;
  Stct_B->Field_2 = 0;
  Stct_B->Field_3 = 0;
  Stct_B->Field_4 = 0;

  return; 
}

/*@
  assigns Stct_B->At_1 [ 0..(SIZE_SECOND - 1) ];
  ensures Reset_At_1(Stct_B, 0, SIZE_SECOND);
*/
void Reset_At_1 (Struct_B * const Stct_B)
{
 /*@
 loop invariant 0 <= Index <= SIZE_SECOND;

 loop invariant Reset_At_1(Stct_B, 0, Index);

 loop assigns Index, Stct_B->At_1 [ 0..(SIZE_SECOND - 1) ];

 loop variant SIZE_SECOND - Index;
*/
  for (int Index = 0; Index < SIZE_SECOND; ++(Index))
  {
    Stct_B->At_1 [ Index ].Field_5 = 0;
    Stct_B->At_1 [ Index ].Field_6 = 0;
  }

  return;
 }

/*@ 
  assigns Stct_B->At_2 [0..(SIZE_THIRD - 1)];
  ensures Reset_At_2(Stct_B, 0, SIZE_THIRD);
*/
void Reset_At_2 (Struct_B * Stct_B)
{

 /*@ 
   loop invariant 0 <= Index <= SIZE_THIRD;

   loop invariant Reset_At_2(Stct_B, 0, Index);

   loop assigns Index, Stct_B->At_2 [0..(SIZE_THIRD - 1)];

   loop variant SIZE_THIRD - Index; 
 */ 
  for (int Index = 0; Index < SIZE_THIRD; ++(Index))
   {
     Stct_B->At_2 [ Index ].Field_5 = 0;
     Stct_B->At_2 [ Index ].Field_6 = 0;
   }  

    return;
 }


/*@ 
   assigns Stct_B->At_3 [0..(SIZE_THIRD - 1)];
   ensures Reset_At_3(Stct_B, 0, SIZE_THIRD);
*/
void Reset_At_3 (Struct_B * Stct_B)
{

  /*@ 
   loop invariant 0 <= Index <= SIZE_THIRD;

   loop invariant Reset_At_3(Stct_B, 0, Index);

   loop assigns Index, Stct_B->At_3 [0..(SIZE_THIRD - 1)];

   loop variant SIZE_THIRD - Index; 
   */ 
  for (int Index = 0; Index < SIZE_THIRD; ++(Index))
   {
     Stct_B->At_3 [ Index ].Field_5 = 0;
     Stct_B->At_3 [ Index ].Field_6 = 0;
   }  

  return;
 }

/*@ 
  assigns * Stct_B;
  ensures Reset_Basics(Stct_B);
  ensures Reset_At_1(Stct_B, 0, SIZE_SECOND);
  ensures Reset_At_2(Stct_B, 0, SIZE_THIRD);
  ensures Reset_At_3(Stct_B, 0, SIZE_THIRD);
*/

void Reset (Struct_B * const Stct_B)
{
   Reset_Basics(Stct_B);
   Reset_At_1(Stct_B);
   Reset_At_2(Stct_B);
   Reset_At_3(Stct_B);

  return;
}
#包括“file.h”
无效初始化(结构A*常量结构A);
无效重置(结构*常数);
无效重置基础(结构*常量);
1处的无效重置(结构*结构);
2处的无效重置(结构*结构);
3处的无效重置(结构*结构);
/*@ 
将Stct_A->分配到[0..(大小_优先-1)];
分配Stct_A->Count;
*/
无效初始化(结构A*常量结构A)
{
/*@
[Stct_B_索引]处的循环不变量0,0,
尺寸(秒);
循环不变量\对于所有整数Stct_B_索引;(0重置_在_2(&(Stct_A->At[Stct_B_索引]),0,
大小(第三);
循环不变量\对于所有整数Stct_B_索引;(0重置_在_3(&(Stct_A->At[Stct_B_索引]),0,
大小(第三);
循环分配索引,Stct_A->At[0..(SIZE_FIRST-1)];
循环变量大小_FIRST-索引;
*/
对于(int Index=0;IndexAt[索引]);
} 
Stct_A->计数=0;
返回;
}
/*@ 
分配*Stct_B;
确保重置基础设施(Stct);
*/
无效重置基础(结构*常量)
{
Stct_B->字段_1=0;
Stct_B->字段_2=0;
Stct_B->字段_3=0;
Stct_B->字段_4=0;
返回;
}
/*@
分配Stct_B->At_1[0..(大小_秒-1)];
确保在_1处重置_(Stct_B,0,大小_秒);
*/
1处的无效重置(结构*常量)
{
/*@
_1[索引]处的循环不变量0。字段_5=0;
Stct_B->At_1[索引]。字段_6=0;
}
返回;
}
/*@ 
分配Stct_B->At_2[0..(大小第三个-1)];
确保在_2处重置_(Stct_B,0,大小为第三);
*/
2处的无效重置(结构*Stct)
{
/*@ 
_2[索引]处的循环不变量0。字段_5=0;
Stct_B->At_2[索引]。字段_6=0;
}  
返回;
}
/*@ 
分配Stct_B->At_3[0..(大小第三个-1)];
确保在3处复位(Stct\U B,0,大小为3);
*/
3处的无效重置(结构*Stct)
{
/*@ 
_3[索引]处的循环不变量0。字段_5=0;
Stct_B->At_3[索引]。字段_6=0;
}  
返回;
}
/*@ 
分配*Stct_B;
确保重置基础设施(Stct);
确保在_1处重置_(Stct_B,0,大小_秒);
确保在_2处重置_(Stct_B,0,大小为第三);
确保在3处复位(Stct\U B,0,大小为3);
*/
无效重置(结构*常数)
{
重置基础(Stct_B);
在_1处重置_(Stct_B);
在2(Stct_B)处重置_;
在3(Stct_B)处重置_;
返回;
}

在我看来,似乎无法保证在调用C后B的后置条件仍然适用。C可能被设计为改变事物,使其不真实。冲洗并重复。话虽如此,我对Frama-C及其断言的含义一无所知。我有点好奇,没有关于前置条件的断言s、 但“温和”是一个有效术语,可能只是为了强调我缺乏任何详细的知识。当仅断言前一个函数调用的后条件时,合同是如何标记的?Frama-c只检查被调用函数的先决条件的可满足性。它假设Action是满意的,不关心函数的实现。现在,我希望上面代码的断言是多余的,但令人惊讶的是,没有断言,函数A的契约变得无效。再次,请发布A。特别是,由于您对
A
调用的函数的契约有问题,pr不管怎样,正如@jonathan leffler所暗示的那样,问题最可能的根源是所述合同缺少
赋值
子句,因此WP无法知道全局状态的哪些部分是由函数
C
D
。。。。因此,在调用
C
之后,无法知道
PostConditionOfB
是否保持。抱歉,延迟了。请