ACSL"指定" C代码的内部结构和字段的注释

时间:2017-04-27 04:36:00

标签: static-analysis frama-c acsl

假设我们有这样的数据结构:

#typedef struct
{
int  C_Field;
}C;

#typedef struct
{
C B_Array[MAX_SIZE];
}B;

#typedef struct
{
 B A_Array[MAX_SIZE];
}A;

在以下示例中,Frama-C似乎没有为C类结构的字段分配位置:

/*@
  assigns Arg->A_Array[0..(MAX_SIZE - 1)].B_Array[0..(MAX_SIZE - 1)].C_Field;
*/
void Initialize (A * Arg);

上面的注释是否可以被Frama-C接受?

代码详述如下。主要目标是将字段C_Field重置为0:

/*@ predicate 
      ResetB (B * Arg) =
        \forall integer Index; 0<= Index < MAX_SIZE ==>
                 Arg -> B_Array[Index].C_Field == 0;
*/

//@ assigns * Arg;
// Even I tried this:
//@ assigns Arg -> A_Array[0..(MAX_SIZE - 1)];
void Initialize (A * Arg)
{
 /*@ loop invariant 0 <= Index <= MAX_SIZE;
     loop invariant ResetB(&(Arg->A_Array[Index]));
     loop assigns Index, Arg -> A_Array[0..(MAX_SIZE - 1)];
 */
 for (int Index = 0; Index < MAX_SIZE; Index++)
  {
    Reset(&(Arg -> A_Array[Index]));
  }
}

/*@ assigns Arg -> B_Array[0..(MAX_SIZE - 1)];
    ensures ResetB(Arg);      
*/
void Reset(B * Arg)
{
 /*@ loop invariant 0 <= Index <= MAX_SIZE;
     loop invariant \forall integer i; 0<= i < Index ==>
                     Arg -> B_Array[i].C_Field == 0;
     loop assigns Index, Arg -> B_Array[0..(MAX_SIZE - 1)];
 */
 for (int Index = 0; Index < MAX_SIZE; Index++)
 {
  Arg -> B_Array[Index].C_Field = 0;
 }
}

函数Reset的合同已经满足,但函数Initialize的合同不是。如何写出正确的&#34;分配&#34;对于Initialize的合同?

1 个答案:

答案 0 :(得分:2)

假设您正在使用插件WP(请参阅上面的评论),您的主要问题是您没有在loop assigns函数中为您的循环编写Initializeloop assigns对于要使用WP的函数中出现的每个循环都是必需的。此外,如果您的合同有ensures条款,则您很可能需要loop invariant,再次针对所分析代码中的每个循环。

<强>更新 使用您提供的代码和frama-c Silicon,唯一未通过frama-c -wp file.c证明的是Initialize中关于ResetB的循环不变量。它未被证明的原因是它是错误的。真正的不变量应该是\forall integer i; 0<=i<Index ==> ResetB(&(Arg->A_Array[i]))。通过以下完整示例,所有内容都已解除,至少在Silicon:

#define MAX_SIZE 100

typedef struct
{
int  C_Field;
int D_Field;
}C;

typedef struct
{
C B_Array[MAX_SIZE];
}B;

typedef struct
{
 B A_Array[MAX_SIZE];
}A;

/*@ predicate 
      ResetB (B * Arg) =
        \forall integer Index; 0<= Index < MAX_SIZE ==>
                 Arg -> B_Array[Index].C_Field == 0;
*/

void Reset(B * Arg);

// @ assigns * Arg;
// Even I tried this:
//@ assigns Arg -> A_Array[0..(MAX_SIZE - 1)];
void Initialize (A * Arg)
{
 /*@ loop invariant 0 <= Index <= MAX_SIZE;
     loop invariant \forall integer i; 0<=i<Index ==> ResetB(&(Arg->A_Array[i]));
     loop assigns Index, Arg -> A_Array[0..(MAX_SIZE - 1)];
 */
 for (int Index = 0; Index < MAX_SIZE; Index++)
  {
    Reset(&(Arg -> A_Array[Index]));
  }
}

/*@ assigns Arg -> B_Array[0..(MAX_SIZE - 1)];
    ensures ResetB(Arg);
*/
void Reset(B * Arg)
{
 /*@ loop invariant 0 <= Index <= MAX_SIZE;
     loop invariant \forall integer i; 0<= i < Index ==>
                     Arg -> B_Array[i].C_Field == 0;
     loop assigns Index, Arg -> B_Array[0..(MAX_SIZE - 1)];
 */
 for (int Index = 0; Index < MAX_SIZE; Index++)
 {
  Arg -> B_Array[Index].C_Field = 0;
 }
}